dtonhofer

dtonhofer

Functional Programming in Java, Second Edition: Functional Programming in Java, Second Edition: JUnit code improvements for Chapter 11, pages 192 ff “Refactoring File Processing”

In this code:

  • We actually create the (temporary) file we want to read and delete it again at the end.
  • Default charsets for reading text files are the work of the devil, we set UTF-8 explicitly.
  • The files need to be properly closed with try-with-resources, this also applies to the stream approach.
  • A “long” count as return value seems excessive, dropping to int.
package chapter11;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class FileProcessingTest {

    private static File actualFile;
    private final static Charset charset = StandardCharsets.UTF_8;

    // Creates a file "/tmp/WordCount13982583023783245787.java" for example

    @BeforeAll
    static void createTmpFile() throws IOException {
        actualFile = File.createTempFile("WordCount", ".java");
        try (FileWriter writer = new FileWriter(actualFile, charset)) {
            writer.write("package foo;\n");
            writer.write("public class X {\n");
            writer.write("}\n");
            writer.write("public class Y {\n");
            writer.write("}\n");
        }
    }

    @AfterAll
    static void deleteTmpFile() throws IOException {
        // or one could have installed a handler with deleteOnExit()
        actualFile.delete();
    }

    interface WordCount {

        int countInFile(String word, File file) throws IOException;

    }

    // https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/io/FileReader.html
    // https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/io/BufferedReader.html

    static class WordCountBefore implements WordCount {

        public int countInFile(final String searchWord, final File file) throws IOException {
            int count = 0;
            // Use try-with-resources / automatic resource management to clean up.
            // Specify the charset, "default chartset" is the devil's work!
            try (final var bufferedReader = new BufferedReader(new FileReader(file, charset))) {
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    final String[] words = line.split(" ");
                    for (String word : words) {
                        if (word.equals(searchWord)) {
                            count++;
                        }
                    }
                }
                return count;
            }
        }
    }

    // https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/nio/file/Files.html

    static class WordCountAfter implements WordCount {

        // The Files.lines() call may throw IOException.
        // Additionally, the count() this yields a "long", so we need to cast to fit the interface.
        // We still must use try-with-resources to close the file.

        public int countInFile(final String searchWord, final File file) throws IOException {
            try (final Stream<String> stream = Files.lines(file.toPath(), charset)) {
                return (int) stream
                        .flatMap(line -> Stream.of(line.split(" ")))
                        .filter(word -> word.equals(searchWord))
                        .count();
            }
        }

    }

    private static void commonFileProcessingTests(final WordCount wordCount, File file) {
        assertAll(
                () -> assertEquals(2, wordCount.countInFile("public", file)),
                () -> assertEquals(1, wordCount.countInFile("package", file)));
    }

    @Test
    void fileProcessingBefore() {
        commonFileProcessingTests(new WordCountBefore(), actualFile);
    }

    @Test
    void fileProcessingAfter() {
        commonFileProcessingTests(new WordCountAfter(), actualFile);
    }

}

Where Next?

Popular Pragmatic Bookshelf topics Top

jimschubert
In Chapter 3, the source for index introduces Config on page 31, followed by more code including tests; Config isn’t introduced until pag...
New
johnp
Running the examples in chapter 5 c under pytest 5.4.1 causes an AttributeError: ‘module’ object has no attribute ‘config’. In particula...
New
jamis
The following is cross-posted from the original Ray Tracer Challenge forum, from a post by garfieldnate. I’m cross-posting it so that the...
New
lirux
Hi Jamis, I think there’s an issue with a test on chapter 6. I own the ebook, version P1.0 Feb. 2019. This test doesn’t pass for me: ...
New
Mmm
Hi, build fails on: bracket-lib = “~0.8.1” when running on Mac Mini M1 Rust version 1.5.0: Compiling winit v0.22.2 error[E0308]: mi...
New
HarryDeveloper
Hi @venkats, It has been mentioned in the description of ‘Supervisory Job’ title that 2 things as mentioned below result in the same eff...
New
akraut
The markup used to display the uploaded image results in a Phoenix.LiveView.HTMLTokenizer.ParseError error. lib/pento_web/live/product_l...
New
taguniversalmachine
Hi, I am getting an error I cannot figure out on my test. I have what I think is the exact code from the book, other than I changed “us...
New
s2k
Hi all, currently I wonder how the Tailwind colours work (or don’t work). For example, in app/views/layouts/application.html.erb I have...
New
roadbike
From page 13: On Python 3.7, you can install the libraries with pip by running these commands inside a Python venv using Visual Studio ...
New

Other popular topics Top

Devtalk
Hello Devtalk World! Please let us know a little about who you are and where you’re from :nerd_face:
New
AstonJ
A thread that every forum needs! Simply post a link to a track on YouTube (or SoundCloud or Vimeo amongst others!) on a separate line an...
New
PragmaticBookshelf
Learn from the award-winning programming series that inspired the Elixir language, and go on a step-by-step journey through the most impo...
New
PragmaticBookshelf
Write Elixir tests that you can be proud of. Dive into Elixir’s test philosophy and gain mastery over the terminology and concepts that u...
New
AstonJ
You might be thinking we should just ask who’s not using VSCode :joy: however there are some new additions in the space that might give V...
New
AstonJ
There’s a whole world of custom keycaps out there that I didn’t know existed! Check out all of our Keycaps threads here: https://forum....
New
AstonJ
Do the test and post your score :nerd_face: :keyboard: If possible, please add info such as the keyboard you’re using, the layout (Qw...
New
PragmaticBookshelf
Tailwind CSS is an exciting new CSS framework that allows you to design your site by composing simple utility classes to create complex e...
New
PragmaticBookshelf
Use WebRTC to build web applications that stream media and data in real time directly from one user to another, all in the browser. ...
New
NewsBot
Node.js v22.14.0 has been released. Link: Release 2025-02-11, Version 22.14.0 'Jod' (LTS), @aduh95 · nodejs/node · GitHub
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: