
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\0
as 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! 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

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

I can’t setup the Rails source code. This happens in a working directory containing multiple (postgres) Rails apps.
With:
ruby-3.0.0
s...
New

Title: Web Development with Clojure, Third Edition, vB17.0 (p9)
The create table guestbook syntax suggested doesn’t seem to be accepted ...
New

A Common-Sense Guide to Data Structures and Algorithms, Second Edition by Jay Wengrow @jaywengrow
Hi,
I have the paperback version of t...
New

“The ProductLive.Index template calls a helper function, live_component/3, that in turn calls on the modal component. ”
Excerpt From: Br...
New

I’m under the impression that when the reader gets to page 136 (“View Data with the Database Inspector”), the code SHOULD be able to buil...
New

The markup used to display the uploaded image results in a Phoenix.LiveView.HTMLTokenizer.ParseError error.
lib/pento_web/live/product_l...
New

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

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

@AstonJ prompted me to open this topic after I mentioned in the lockdown thread how I started to do a lot more for my fitness.
https://f...
New

New

SpaceVim seems to be gaining in features and popularity and I just wondered how it compares with SpaceMacs in 2020 - anyone have any thou...
New
New

Just done a fresh install of macOS Big Sur and on installing Erlang I am getting:
asdf install erlang 23.1.2
Configure failed.
checking ...
New

Author Spotlight
James Stanier
@jstanier
James Stanier, author of Effective Remote Work , discusses how to rethink the office as we e...
New

Inside our android webview app, we are trying to paste the copied content from another app eg (notes) using navigator.clipboard.readtext ...
New

Hello,
I’m a beginner in Android development and I’m facing an issue with my project setup. In my build.gradle.kts file, I have the foll...
New

Curious what kind of results others are getting, I think actually prefer the 7B model to the 32B model, not only is it faster but the qua...
New

Background
Lately I am in a quest to find a good quality TTS ai generation tool to run locally in order to create audio for some videos I...
New
Categories:
Sub Categories:
Popular Portals
- /elixir
- /rust
- /ruby
- /wasm
- /erlang
- /phoenix
- /keyboards
- /rails
- /js
- /python
- /security
- /go
- /swift
- /vim
- /clojure
- /emacs
- /haskell
- /java
- /onivim
- /svelte
- /typescript
- /crystal
- /c-plus-plus
- /kotlin
- /tailwind
- /gleam
- /ocaml
- /react
- /elm
- /flutter
- /vscode
- /ash
- /opensuse
- /centos
- /php
- /deepseek
- /html
- /zig
- /scala
- /sublime-text
- /textmate
- /debian
- /nixos
- /lisp
- /react-native
- /agda
- /kubuntu
- /arch-linux
- /django
- /revery
- /ubuntu
- /spring
- /manjaro
- /diversity
- /nodejs
- /lua
- /slackware
- /julia
- /c
- /neovim