user2718135
user2718135

Reputation:

Writing HashMap contents to the file

I have a HashMap<Integer, Integer>. I write its content to the file, so each line of it contains hashmapKey:::hashmapValue. This is how I do it now:

List<String> mLines = new ArrayList<String>();
mHashMap.forEach((key, value) -> mLines.add(key + DATA_SEPARATOR + value));
Files.write(mOutputPath, mLines, StandardCharsets.UTF_8);

I very doubt that I need to copy entire HashMap to the list of strings, I am sure it will give me performance issues when working with big amounts of data. My question is: how can I write HashMap contents to the file using Java 8 avoiding copying values in another list?

Upvotes: 9

Views: 15606

Answers (4)

Holger
Holger

Reputation: 298143

The simplest, non-copying, most “streamish” solution is

Files.write(mOutputPath, () -> mHashMap.entrySet().stream()
    .<CharSequence>map(e -> e.getKey() + DATA_SEPARATOR + e.getValue())
    .iterator());

While a Stream does not implement Iterable, a lambda expression performing a Stream operation that ends with calling iterator() on the stream, can be. It will fulfill the contract as the lambda expression will, unlike a Stream, produce a new Iterator on each invocation.

Note that I removed the explicit UTF-8 character set specifier as java.nio.Files will use UTF-8 when no charset is specified (unlike the old io classes).

The neat thing about the above solution is that the I/O operation wraps the Stream processing, so inside the Stream, we don’t have to deal with checked exceptions. In contrast, the Writer+forEach solution needs to handle IOExceptions as a BiConsumer is not allowed to throw checked exceptions. As a result, a working solution using forEach would look like:

try(Writer writer = Files.newBufferedWriter(mOutputPath)) {
    mHashMap.forEach((key, value) -> {
        try { writer.write(key + DATA_SEPARATOR + value + System.lineSeparator()); }
        catch (IOException ex) { throw new UncheckedIOException(ex); }
    });
} catch(UncheckedIOException ex) { throw ex.getCause(); }

Upvotes: 17

Gerald M&#252;cke
Gerald M&#252;cke

Reputation: 11122

You could map the entries of the map to a string and write them to a FileChannel. The additional methods simply do the exception handling so the stream operations become more readable.

final Charset charset =  Charset.forName("UTF-8");
try(FileChannel fc = FileChannel.open(mOutputPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)) {
    mHashMap.entrySet().stream().map(e -> e.getKey() + ":::" + e.getValue() + "\n")
            .map(s -> encode(charset, s))
            .forEach(bb -> write(fc, bb));
}

void write(FileChannel fc, ByteBuffer bb){
    try {
        fc.write(bb);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

ByteBuffer encode( Charset charset, String string){
    try {
        return charset.newEncoder().encode(CharBuffer.wrap(string));
    } catch (CharacterCodingException e) {
        throw new RuntimeException(e);
    }
}

Upvotes: 0

uniknow
uniknow

Reputation: 938

HashMap implements Serializable so you should be able to use standard serialization to write hashmap to file.

Example:

HashMap<Integer, String> hmap = new HashMap<Integer, String>();

//Adding elements to HashMap

try {
    FileOutputStream fos =
            new FileOutputStream("example.ser");
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    oos.writeObject(hmap);
    oos.close();
    fos.close();
}catch(IOException ioe) {
    ioe.printStackTrace();
} 

Upvotes: -2

Robert
Robert

Reputation: 42585

You can simply avoid using a List<String> by directly writing out the lines to disk using e.g. a Writer:

    Writer writer = new BufferedWriter(new OutputStreamWriter(
            new FileOutputStream(new File(mOutputPath)), StandardCharsets.UTF_8));
    mHashMap.forEach((key, value) -> writer.write(key + DATA_SEPARATOR + value + System.lineSeparator()));
    writer.flush();
    writer.close();

Upvotes: 3

Related Questions