dtonhofer

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()));
    }

}

Where Next?

Popular Pragmatic Bookshelf topics Top

iPaul
page 37 ANTLRInputStream input = new ANTLRInputStream(is); as of ANTLR 4 .8 should be: CharStream stream = CharStreams.fromStream(i...
New
telemachus
Python Testing With Pytest - Chapter 2, warnings for “unregistered custom marks” While running the smoke tests in Chapter 2, I get these...
New
Mmm
Hi, build fails on: bracket-lib = “~0.8.1” when running on Mac Mini M1 Rust version 1.5.0: Compiling winit v0.22.2 error[E0308]: mi...
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
hgkjshegfskef
The test is as follows: Scenario: Intersecting a scaled sphere with a ray Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) And s ← sphere...
New
jskubick
I found an issue in Chapter 7 regarding android:backgroundTint vs app:backgroundTint. How to replicate: load chapter-7 from zipfile i...
New
brunogirin
When I run the coverage example to report on missing lines, I get: pytest --cov=cards --report=term-missing ch7 ERROR: usage: pytest [op...
New
New
Keton
When running the program in chapter 8, “Implementing Combat”, the printout Health before attack was never printed so I assumed something ...
New
mcpierce
@mfazio23 I’ve applied the changes from Chapter 5 of the book and everything builds correctly and runs. But, when I try to start a game,...
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
DevotionGeo
I know that these benchmarks might not be the exact picture of real-world scenario, but still I expect a Rust web framework performing a ...
New
Exadra37
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
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
poll poll Be sure to check out @Dusty’s article posted here: An Introduction to Alternative Keyboard Layouts It’s one of the best write-...
New
AstonJ
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
AstonJ
I ended up cancelling my Moonlander order as I think it’s just going to be a bit too bulky for me. I think the Planck and the Preonic (o...
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
AstonJ
This is cool! DEEPSEEK-V3 ON M4 MAC: BLAZING FAST INFERENCE ON APPLE SILICON We just witnessed something incredible: the largest open-s...
New
PragmaticBookshelf
A concise guide to MySQL 9 database administration, covering fundamental concepts, techniques, and best practices. Neil Smyth MySQL...
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: