Reputation:
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
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 IOException
s 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
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
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
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