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);
}
}
Popular Pragmatic Bookshelf topics
page 37
ANTLRInputStream input = new ANTLRInputStream(is);
as of ANTLR 4 .8 should be:
CharStream stream = CharStreams.fromStream(i...
New
Following the steps described in Chapter 6 of the book, I’m stuck with running the migration as described on page 84:
bundle exec sequel...
New
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
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
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
Hi! I know not the intentions behind this narrative when called, on page XI:
mount() |> handle_event() |> render()
but the correc...
New
In case this helps anyone, I’ve had issues setting up the rails source code. Here were the solutions:
In Gemfile, change
gem 'rails'
t...
New
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
Hi, I need some help, I’m new to rust and was learning through your book. but I got stuck at the last stage of distribution. Whenever I t...
New
Hi, I’ve got a question about the implementation of PubSub when using a Phoenix.Socket.Transport behaviour rather than channels.
Before ...
New
Other popular topics
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
Which, if any, games do you play? On what platform?
I just bought (and completed) Minecraft Dungeons for my Nintendo Switch. Other than ...
New
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
Rust is an exciting new programming language combining the power of C with memory safety, fearless concurrency, and productivity boosters...
New
New
Hello everyone! This thread is to tell you about what authors from The Pragmatic Bookshelf are writing on Medium.
New
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
If you want a quick and easy way to block any website on your Mac using Little Snitch simply…
File > New Rule:
And select Deny, O...
New
Use advanced functional programming principles, practical Domain-Driven Design techniques, and production-ready Elixir code to build scal...
New
Woke up to this today: Claude Code’s complete source code exposed via npm source map. Not a snippet. All 512,000 lines. 1,900 TypeScript ...
New
Categories:
Sub Categories:
Popular Portals
- /elixir
- /rust
- /wasm
- /ruby
- /erlang
- /phoenix
- /keyboards
- /python
- /js
- /rails
- /security
- /go
- /swift
- /vim
- /clojure
- /java
- /emacs
- /haskell
- /svelte
- /onivim
- /typescript
- /kotlin
- /c-plus-plus
- /crystal
- /tailwind
- /react
- /gleam
- /ocaml
- /elm
- /flutter
- /vscode
- /ash
- /html
- /opensuse
- /deepseek
- /zig
- /centos
- /php
- /scala
- /react-native
- /lisp
- /textmate
- /sublime-text
- /nixos
- /debian
- /agda
- /deno
- /django
- /kubuntu
- /arch-linux
- /nodejs
- /spring
- /ubuntu
- /revery
- /manjaro
- /lua
- /julia
- /diversity
- /markdown
- /c









