dtonhofer
Functional Programming in Java, Second Edition: Functional Programming in Java, Second Edition: JUnit code improvements for Chapter 11, pages 189 ff “Refactoring to Rework the Logic”
The usual changes but:
- The “FirstRepeatedLetter.findIn()” has been improved out of the box. In particular returning ‘\0’ is too C-like and smells like “primitive obsession”. We have
null, we should use it. What if the input contains\0as the matching character? - A slightly better code (IMHO) is in
FirstRepeatedLetterBetter.findIn() - The final refactored code returns not null, but
Optional<Character>, which is cleaner. - Again, for testing we use a common interface or a wrapper class to avoid having to duplicate testing code.
package chapter11;
import org.junit.jupiter.api.Test;
import java.util.Optional;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
public class ReworkTheLogicTest {
interface FindLetter {
Character findIn(String word);
}
static class FirstRepeatedLetterBefore implements FindLetter {
public Character findIn(final String word) {
final char[] letters = word.toCharArray();
for (char candidate : letters) {
int count = 0;
for (char letter : letters) {
if (candidate == letter) {
count++;
}
}
if (count > 1) {
return candidate;
}
}
return null;
}
}
static class FirstRepeatedLetterBetter implements FindLetter {
public Character findIn(final String word) {
char[] letters = word.toCharArray();
int i = 0;
Character found = null;
while (i < letters.length && found == null) {
// will letter[i] been seen again?
char maybe = letters[i];
int j = i + 1;
while (j < letters.length && letters[j] != maybe) j++;
if (j < letters.length) {
found = maybe;
} else {
i++;
}
}
return found;
}
}
// Does NOT implement "FindLetter", returns Optional<Character>
static class FirstRepeatedLetterAfter {
public Optional<Character> findIn(final String word) {
return Stream.of(word.split(""))
.filter(letter -> word.lastIndexOf(letter) > word.indexOf(letter))
.findFirst()
.map(letter -> letter.charAt(0));
}
}
static class FirstRepeatedLetterAfterWrapped implements FindLetter {
private final FirstRepeatedLetterAfter finder;
public FirstRepeatedLetterAfterWrapped(FirstRepeatedLetterAfter finder) {
this.finder = finder;
}
public Character findIn(final String word) {
return finder.findIn(word).orElse(null);
}
}
private static void commonFindFirstRepeatingTests(final FindLetter finder) {
assertAll(
() -> assertEquals('l', finder.findIn("hello")),
() -> assertEquals('h', finder.findIn("hellothere")),
() -> assertEquals('a', finder.findIn("magicalguru")),
() -> assertEquals('z', finder.findIn("abcdefghijklmnopqrstuvwxyzz")),
() -> assertNull(finder.findIn("once")),
() -> assertNull(finder.findIn(""))
);
}
@Test
void findFirstRepeatingBefore() {
commonFindFirstRepeatingTests(new FirstRepeatedLetterBefore());
}
@Test
void findFirstRepeatingBetter() {
commonFindFirstRepeatingTests(new FirstRepeatedLetterBetter());
}
@Test
void findFirstRepeatingAfter() {
commonFindFirstRepeatingTests(new FirstRepeatedLetterAfterWrapped(new FirstRepeatedLetterAfter()));
}
}
Popular Pragmatic Bookshelf topics
Hello Brian,
I have some problems with running the code in your book. I like the style of the book very much and I have learnt a lot as...
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
your book suggests to use Image.toByteData() to convert image to bytes, however I get the following error: "the getter ‘toByteData’ isn’t...
New
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
This isn’t directly about the book contents so maybe not the right forum…but in some of the code apps (e.g. turbo/06) it sends a TURBO_ST...
New
The book has the same “Problem space/Solution space” diagram on page 18 as is on page 17. The correct Problem/Solution space diagrams ar...
New
I ran this command after installing the sample application:
$ cards add do something --owner Brian
And got a file not found error:
Fil...
New
When trying to run tox in parallel as explained on page 151, I got the following error:
tox: error: argument -p/–parallel: expected one...
New
Docker-Machine became part of the Docker Toolbox, which was deprecated in 2020, long after Docker Desktop supported Docker Engine nativel...
New
Getting an error when installing the dependencies at the start of this chapter:
could not compile dependency :exla, "mix compile" failed...
New
Other popular topics
Take your Go skills to the next level by learning how to design, develop, and deploy a distributed service. Start from the bare essential...
New
Algorithms and data structures are much more than abstract concepts. Mastering them enables you to write code that runs faster and more e...
New
Free and open source software is the default choice for the technologies that run our world, and it’s built and maintained by people like...
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
Please tell us what is your preferred monitor setup for programming(not gaming) and why you have chosen it.
Does your monitor have eye p...
New
This looks like a stunning keycap set :orange_heart:
A LEGENDARY KEYBOARD LIVES ON
When you bought an Apple Macintosh computer in the e...
New
Oh just spent so much time on this to discover now that RancherOS is in end of life but Rancher is refusing to mark the Github repo as su...
New
A few weeks ago I started using Warp a terminal written in rust. Though in it’s current state of development there are a few caveats (tab...
New
Author Spotlight
Erin Dees
@undees
Welcome to our new author spotlight! We had the pleasure of chatting with Erin Dees, co-author of ...
New
A concise guide to MySQL 9 database administration, covering fundamental concepts, techniques, and best practices.
Neil Smyth
MySQL...
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
- /flutter
- /elm
- /vscode
- /ash
- /html
- /opensuse
- /deepseek
- /zig
- /centos
- /php
- /scala
- /react-native
- /lisp
- /textmate
- /sublime-text
- /nixos
- /debian
- /agda
- /django
- /deno
- /kubuntu
- /arch-linux
- /nodejs
- /ubuntu
- /spring
- /revery
- /manjaro
- /diversity
- /lua
- /julia
- /markdown
- /slackware









