HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Text file manipulation with Java 8 and Guava

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
filewithtextjavamanipulationguavaand

Problem

I am trying to do some translation of text files. I have a translation .csv file and a file I need to translate (tab delimited). The translation is creating a file with an extra column of the translation.

I'd like to hear any suggestions on this.

```
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.io.Files;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TextFileManipulationExample {

public static void main(String[] args) {
new TextFileManipulationExample().translate();
}

private void translate() {
List translationFileContent = readFile("dictionary.csv");
Stream> translationLines = translationFileContent.stream().map(
line -> Splitter.on(",").splitToList(line));
Map, String> translationMap = translationLines.collect(Collectors.toMap(l -> Lists.newArrayList(l.subList(0, 2)), l -> l.get(2)));
List toTranslateLines = readFile("file_to_translate.txt");
Stream> listWithTranslation = toTranslateLines.stream().map(line -> {
List list = Lists.newArrayList(Splitter.on("\t").splitToList(line));
if (translationMap.containsKey(list)) {
list.add(translationMap.get(list));
}
return list;
});
String contentToWrite = listWithTranslation.map(lineList -> Joiner.on(",").join(lineList)).collect(
Collectors.toList()).stream().reduce((t, u) -> t + "\n" + u).get();
writeFile(contentToWrite, "translated.csv");
}

private void writeFile(String contentToWrite, String fileName) {
try {
Files.write(contentToWrite, new File(fileName), Charset.defaultCharset());
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private List readFile(String fileName) {
try {
return Files.readLines(new File(fileName), Ch

Solution

You are using Java 8's functional stream programming, but you leave out method chaining. Depending on how you chain methods, it could be more or it could be less readable. You might be imagining this:

readFile("dictionary.csv").stream().map(line -> Splitter.on(",").splitToList(line)).collect(Collectors.toMap(l -> Lists.newArrayList(l.subList(0, 2)), l -> l.get(2)));


There is no way I could read that. However, consider this:

Map, String> translationMap = readFile("dictionary.csv").stream()
            .map(line -> Splitter.on(",").splitToList(line))
            .collect(
                Collectors.toMap(
                    l -> Lists.newArrayList(l.subList(0, 2)),
                    l -> l.get(2)
                )
            );


I find this much more readable. By simply reading vertically, I can determine that the code does this:

  • Reads dictionary.csv into a list of strings (via readFile).



  • Split each string in the dictionary on ",", into a List.



  • Collect the Lists into a Map, where



  • The keys are the first two elements of each list, still in a List



  • The values are the 3rd element of each list.



On the other hand, your code as is is littered with type names; do I really need to know that that is a Stream> when that's easily determined from context?:

List translationFileContent = readFile("dictionary.csv");
Stream> translationLines = translationFileContent.stream().map(
  line -> Splitter.on(",").splitToList(line));
Map, String> translationMap = translationLines.collect(Collectors.toMap(l -> Lists.newArrayList(l.subList(0, 2)), l -> l.get(2)));


Alternatively, if you really like the temporary variables, put some empty lines in there to separate logical sections. Also, consider using Project Lombok, where you could just do this:

List translationFileContent = readFile("dictionary.csv");
val translationLines = translationFileContent.stream().map(
    line -> Splitter.on(",").splitToList(line));
val translationMap = translationLines.collect(Collectors.toMap(l -> Lists.newArrayList(l.subList(0, 2)), l -> l.get(2)));


(Coder discretion advised on where you should use val).

Code Snippets

readFile("dictionary.csv").stream().map(line -> Splitter.on(",").splitToList(line)).collect(Collectors.toMap(l -> Lists.newArrayList(l.subList(0, 2)), l -> l.get(2)));
Map<List<String>, String> translationMap = readFile("dictionary.csv").stream()
            .map(line -> Splitter.on(",").splitToList(line))
            .collect(
                Collectors.toMap(
                    l -> Lists.newArrayList(l.subList(0, 2)),
                    l -> l.get(2)
                )
            );
List<String> translationFileContent = readFile("dictionary.csv");
Stream<List<String>> translationLines = translationFileContent.stream().map(
  line -> Splitter.on(",").splitToList(line));
Map<List<String>, String> translationMap = translationLines.collect(Collectors.toMap(l -> Lists.newArrayList(l.subList(0, 2)), l -> l.get(2)));
List<String> translationFileContent = readFile("dictionary.csv");
val translationLines = translationFileContent.stream().map(
    line -> Splitter.on(",").splitToList(line));
val translationMap = translationLines.collect(Collectors.toMap(l -> Lists.newArrayList(l.subList(0, 2)), l -> l.get(2)));

Context

StackExchange Code Review Q#108363, answer score: 3

Revisions (0)

No revisions yet.