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

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
jeffmcompsci
Title: Design and Build Great Web APIs - typo “https://company-atk.herokuapp.com/2258ie4t68jv” (page 19, third bullet in URL list) Typo:...
New
jesse050717
Title: Web Development with Clojure, Third Edition, pg 116 Hi - I just started chapter 5 and I am stuck on page 116 while trying to star...
New
raul
Hi Travis! Thank you for the cool book! :slight_smile: I made a list of issues and thought I could post them chapter by chapter. I’m rev...
New
raul
Page 28: It implements io.ReaderAt on the store type. Sorry if it’s a dumb question but was the io.ReaderAt supposed to be io.ReadAt? ...
New
brian-m-ops
#book-python-testing-with-pytest-second-edition Hi. Thanks for writing the book. I am just learning so this might just of been an issue ...
New
AndyDavis3416
@noelrappin Running the webpack dev server, I receive the following warning: ERROR in tsconfig.json TS18003: No inputs were found in c...
New
jgchristopher
“The ProductLive.Index template calls a helper function, live_component/3, that in turn calls on the modal component. ” Excerpt From: Br...
New
dtonhofer
@parrt In the context of Chapter 4.3, the grammar Java.g4, meant to parse Java 6 compilation units, no longer passes ANTLR (currently 4....
New
davetron5000
Hello faithful readers! If you have tried to follow along in the book, you are asked to start up the dev environment via dx/build and ar...
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
PragmaticBookshelf
Brace yourself for a fun challenge: build a photorealistic 3D renderer from scratch! In just a couple of weeks, build a ray tracer that r...
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
ohm
Which, if any, games do you play? On what platform? I just bought (and completed) Minecraft Dungeons for my Nintendo Switch. Other than ...
New
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
AstonJ
Continuing the discussion from Thinking about learning Crystal, let’s discuss - I was wondering which languages don’t GC - maybe we can c...
New
PragmaticBookshelf
Author Spotlight Jamis Buck @jamis This month, we have the pleasure of spotlighting author Jamis Buck, who has written Mazes for Prog...
New
hilfordjames
There appears to have been an update that has changed the terminology for what has previously been known as the Taskbar Overflow - this h...
New
PragmaticBookshelf
Fight complexity and reclaim the original spirit of agility by learning to simplify how you develop software. The result: a more humane a...
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: