Word count example in Java 8

Following code snippet shows how you can write a word count program using Java 8 Stream API.

public class WordCountExample {

    public static void main(String[] args) throws IOException {
        Path path = Paths.get("src/main/resources/book.txt");
        Map<String, Integer> wordCount = Files.lines(path)
           .flatMap(line -> Arrays.stream(line.trim().split(" ")))
           .map(word -> word.replaceAll("[^a-zA-Z]", "").toLowerCase().trim())
           .filter(word -> word.length() > 0)
           .map(word -> new SimpleEntry<>(word, 1))
           .sorted((e1, e2) -> e1.getKey().compareTo(e2.getKey()))
            .reduce(new LinkedHashMap<>(), (acc, entry) -> {
               acc.put(entry.getKey(), acc.compute(entry.getKey(), (k, v) -> v == null ? 1 : v + 1));
               return acc;
            }, (m1, m2) -> m1);

        wordCount.forEach((k, v) -> System.out.println(String.format("%s ==>> %d", k, v)));
    }
}

The better solution is using toMap collector as shown below.

public static void main(String[] args) throws IOException {
   Path path = Paths.get("src/main/resources/book.txt");
   Map<String, Integer> wordCount = Files.lines(path).flatMap(line -> Arrays.stream(line.trim().split("s")))
           .map(word -> word.replaceAll("[^a-zA-Z]", "").toLowerCase().trim())
           .filter(word -> word.length() > 0)
           .map(word -> new SimpleEntry<>(word, 1))
           .collect(toMap(e -> e.getKey(), e -> e.getValue(), (v1, v2) -> v1 + v2));

   wordCount.forEach((k, v) -> System.out.println(String.format("%s ==>> %d", k, v)));
}

Even better version can be written using grouping and counting collector as shown below.

public static void main(String[] args) throws IOException {
    Path path = Paths.get("src/main/resources/book.txt");
    Map<String, Long> wordCount = Files.lines(path).flatMap(line -> Arrays.stream(line.trim().split("\s")))
            .map(word -> word.replaceAll("[^a-zA-Z]", "").toLowerCase().trim())
            .filter(word -> word.length() > 0)
            .map(word -> new SimpleEntry<>(word, 1))
            .collect(groupingBy(SimpleEntry::getKey, counting()));

    wordCount.forEach((k, v) -> System.out.println(String.format("%s ==>> %d", k, v)));

}

Day 3: Let’s collect data using Stream API

On day 2, you learned that Stream API can help you work with collections in a declarative manner. We looked at the collect method, which is a terminal operation that collects the result set of a stream pipeline in a List. The collect method is a reduction operation that reduces a stream to a collection. The collect method takes a Collector which let us implement functionalities like group by, partitioning, very easily. Continue reading “Day 3: Let’s collect data using Stream API”

Day 2 — Let’s learn about Streams

On day 1, we learnt how lambdas can help us write clean concise code by allowing us to pass behavior without the need to create a class. Lambdas is a very simple language construct that helps developer express their intent on the fly by using functional interfaces. The real power of lambdas can be experienced when an API is designed keeping lambdas in mind i.e. a fluent API that makes use of Functional interfaces(we discussed them on day 1). Continue reading “Day 2 — Let’s learn about Streams”