I can output sorted entries from a HashMap
like this:
public static void sortAverageTime(HashMap<String, Integer> noSortedMap) {
noSortedMap.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.forEach(x -> System.out.println(x + "ms"));
}
But now I need to write the entries into a file. I'm doing this:
try {
File file = new File("newfile.txt");
if (!file.exists())
file.createNewFile();
FileWriter fw = new FileWriter(file, true);
averageTime.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.forEach(x -> fw.write(x + "ms"));
fw.write("---" + currentDate + "\n");
fw.close();
}
An error is displayed:
Unhandled exception: java.io.IOException.
How can I output sorted entries from a HashMap
to a file?
Placing IO-operations like writing to a file is not a good idea because exception-handling plumbing code completely defeats the readability of lambda expressions.
The primary reason why function programming was introduced in Java is to provide the better way of structuring the code, loops are always more performant than sequential streams.
I suggest to address this problem in two separate steps: first, prepare the data and then write it into a file.
Preparing the data will entail:
String
and adding a time-unit of "ms"
;The first step might look like this:
public static List<String> getSortedData(Map<String, Integer> averageTime) {
return averageTime.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.map(entry -> String.format("%s %d %s", entry.getKey(), entry.getValue(), "ms"))
.collect(Collectors.toList());
}
Writing to a file (for better performance FileWriter
is wrapped into a BufferedWriter
)
public static void sortAverageTime(Map<String, Integer> averageTime,
String fileName) {
File file = new File(fileName);
if (!file.exists())
file.createNewFile();
List<String> sortedData = getSortedData(averageTime);
sortedData.add("---" + LocalDate.now()); // replacement for fw.write("---" + currentDate + "\n")
try(BufferedWriter writer = new BufferedWriter(new FileWriter(file, true))) {
for (String next: sortedData) {
writer.write(next);
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
And with Java NIO the second step could be simplified to:
public static void sortAverageTime(Map<String, Integer> averageTime,
String fileName) {
File file = new File(fileName);
if (!file.exists())
file.createNewFile();
List<String> sortedData = getSortedData(averageTime);
sortedData.add("---" + LocalDate.now());
try {
Files.write(file.toPath(), sortedData, StandardOpenOption.APPEND);
} catch (IOException e) {
e.printStackTrace();
}
}
A couple of important notes:
Never close resources inside the try
block, if exception occur the resource will get never released. For that can either use try with resources (which is a preferred way), explicitly invoke close()
in the finally
block.
Usage of the forEach()
operation is discouraged by the documentation in situations when there's an alternative way to achieve the same result. So the approach of writing to the file from stream is bad on all counts:
- it decries readability;
- it makes your method less narrow-focused and harder to test;
- it is not aligned with the documentation.