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

telemachus
Python Testing With Pytest - Chapter 2, warnings for “unregistered custom marks” While running the smoke tests in Chapter 2, I get these...
New
brianokken
Many tasks_proj/tests directories exist in chapters 2, 3, 5 that have tests that use the custom markers smoke and get, which are not decl...
New
jdufour
Hello! On page xix of the preface, it says there is a community forum "… for help if your’re stuck on one of the exercises in this book… ...
New
joepstender
The generated iex result below should list products instead of product for the metadata. (page 67) iex&gt; product = %Product{} %Pento....
New
rmurray10127
Title: Intuitive Python: docker run… denied error (page 2) Attempted to run the docker command in both CLI and Powershell PS C:\Users\r...
New
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
a.zampa
@mfazio23 I’m following the indications of the book and arriver ad chapter 10, but the app cannot be compiled due to an error in the Bas...
New
New
bjnord
Hello @herbert ! Trying to get the very first “Hello, Bracket Terminal!" example to run (p. 53). I develop on an Amazon EC2 instance runn...
New

Other popular topics Top

brentjanderson
Bought the Moonlander mechanical keyboard. Cherry Brown MX switches. Arms and wrists have been hurting enough that it’s time I did someth...
New
DevotionGeo
I know that -t flag is used along with -i flag for getting an interactive shell. But I cannot digest what the man page for docker run com...
New
AstonJ
I’ve been hearing quite a lot of comments relating to the sound of a keyboard, with one of the most desirable of these called ‘thock’, he...
New
Margaret
Hello everyone! This thread is to tell you about what authors from The Pragmatic Bookshelf are writing on Medium.
1147 29994 760
New
AstonJ
We’ve talked about his book briefly here but it is quickly becoming obsolete - so he’s decided to create a series of 7 podcasts, the firs...
New
PragmaticBookshelf
Author Spotlight Rebecca Skinner @RebeccaSkinner Welcome to our latest author spotlight, where we sit down with Rebecca Skinner, auth...
New
New
sir.laksmana_wenk
I’m able to do the “artistic” part of game-development; character designing/modeling, music, environment modeling, etc. However, I don’t...
New
AstonJ
This is a very quick guide, you just need to: Download LM Studio: https://lmstudio.ai/ Click on search Type DeepSeek, then select the o...
New
mindriot
Ok, well here are some thoughts and opinions on some of the ergonomic keyboards I have, I guess like mini review of each that I use enoug...
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: