
dtonhofer
Functional Programming in Java, Second Edition: Functional Programming in Java, Second Edition: JUnit code improvements for Chapter 11, pages 185 ff “Refactoring Unbounded Loops”
The same remarks apply as for “Refactoring the Traditional for Loop”
- No init()
- Negative tests which apply for input less than 1900, resulting in exceptions.
but we cannot implement a common interface as the method parameters change. So we wrap the new class into a class that obeys the old interface, which agains llaows us to use the same test code to test both odl and new classes.
There is also a little tweak to the semantics of the case where 1900 is already rejected - instead of returning 0, we throw. Because there basically is no result in that case.
package chapter11;
import org.junit.jupiter.api.Test;
import java.time.Year;
import java.util.function.Predicate;
import java.util.stream.IntStream;
import static org.junit.jupiter.api.Assertions.*;
public class UnboundedLoopTest {
interface Continue {
boolean check(int year);
}
interface WithContinue {
int countFrom1900(final Continue shouldContinue);
}
static class LeapYearsUnboundedBefore implements WithContinue {
public int countFrom1900(final Continue shouldContinue) {
if (!shouldContinue.check(1900)) {
throw new IllegalArgumentException("Cannot 'continue' right at the start!'");
}
int count = 0;
for (int year = 1900; ; year += 4) {
if (!shouldContinue.check(year)) {
break;
}
if (Year.isLeap(year)) {
count++;
}
}
return count;
}
}
// Does NOT implement WithContinue!!
static class LeapYearsUnboundedAfter {
public int countFrom1900(final Predicate<Integer> shouldContinue) {
if (!shouldContinue.test(1900)) {
throw new IllegalArgumentException("Cannot 'continue' right at the start!'");
}
return (int) IntStream.iterate(1900, year -> year + 4)
.takeWhile(shouldContinue::test)
.filter(Year::isLeap)
.count();
}
}
static class LeapYearsUnboundedAfterWrapped implements WithContinue {
private final LeapYearsUnboundedAfter ly;
public LeapYearsUnboundedAfterWrapped(LeapYearsUnboundedAfter ly) {
this.ly = ly;
}
public int countFrom1900(final Continue shouldContinue) {
return ly.countFrom1900(year -> shouldContinue.check(year));
}
}
// One should maybe have a separate method to test the throws
private static void commonLeapYearsTests(final WithContinue withContinue) {
assertAll(
() -> assertEquals(0, withContinue.countFrom1900(year -> year <= 1900)),
() -> assertEquals(25, withContinue.countFrom1900(year -> year <= 2000)),
() -> assertEquals(27, withContinue.countFrom1900(year -> year <= 2010)),
() -> assertEquals(31, withContinue.countFrom1900(year -> year <= 2025)),
() -> assertEquals(49, withContinue.countFrom1900(year -> year <= 2100)),
() -> assertEquals(267, withContinue.countFrom1900(year -> year <= 3000)),
() -> assertThrows(IllegalArgumentException.class, () ->
withContinue.countFrom1900(year -> year < 1800)
),
() -> assertThrows(IllegalArgumentException.class, () ->
withContinue.countFrom1900(year -> year < 1900)
)
);
}
@Test
void leapYearCountBefore() {
commonLeapYearsTests(new LeapYearsUnboundedBefore());
}
@Test
void leapYearCountAfter() {
commonLeapYearsTests(new LeapYearsUnboundedAfterWrapped(new LeapYearsUnboundedAfter()));
}
}
Popular Pragmatic Bookshelf topics

In Chapter 3, the source for index introduces Config on page 31, followed by more code including tests; Config isn’t introduced until pag...
New

Title: Design and Build Great Web APIs - typo “https://company-atk.herokuapp.com/2258ie4t68jv” (page 19, third bullet in URL list)
Typo:...
New

When I try the command to create a pair of migration files I get an error.
user=> (create-migration "guestbook")
Execution error (Ill...
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

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

I am working on the “Your Turn” for chapter one and building out the restart button talked about on page 27. It recommends looking into ...
New

On page 78 the following code appears:
<%= link_to ‘Destroy’, product,
class: ‘hover:underline’,
method: :delete,
data: { confirm...
New

When running the program in chapter 8, “Implementing Combat”, the printout Health before attack was never printed so I assumed something ...
New

Docker-Machine became part of the Docker Toolbox, which was deprecated in 2020, long after Docker Desktop supported Docker Engine nativel...
New

I’ve got to the end of Ch. 11, and the app runs, with all tabs displaying what they should – at first. After switching around between St...
New
Other popular topics

Reading something? Working on something? Planning something? Changing jobs even!?
If you’re up for sharing, please let us know what you’...
New

I have seen the keycaps I want - they are due for a group-buy this week but won’t be delivered until October next year!!! :rofl:
The Ser...
New

“Finding the Boundaries” Hero’s Journey with Noel Rappin @noelrappin
Even when you’re ultimately right about what the future ho...
New

The V Programming Language
Simple language for building maintainable programs
V is already mentioned couple of times in the forum, but I...
New

API 4
Path:
/user/following/
Method:
GET
Description:
Returns the list of all names of people whom the user follows
Response
[
{ ...
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

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

Author Spotlight:
Karl Stolley
@karlstolley
Logic! Rhetoric! Prag! Wow, what a combination. In this spotlight, we sit down with Karl ...
New

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

Author Spotlight:
Tammy Coron
@Paradox927
Gaming, and writing games in particular, is about passion, vision, experience, and immersio...
New
Categories:
Sub Categories:
Popular Portals
- /elixir
- /rust
- /wasm
- /ruby
- /erlang
- /phoenix
- /keyboards
- /rails
- /js
- /python
- /security
- /go
- /swift
- /vim
- /clojure
- /emacs
- /haskell
- /java
- /onivim
- /svelte
- /typescript
- /crystal
- /kotlin
- /c-plus-plus
- /tailwind
- /gleam
- /ocaml
- /react
- /elm
- /flutter
- /vscode
- /ash
- /opensuse
- /centos
- /html
- /php
- /deepseek
- /zig
- /scala
- /lisp
- /textmate
- /sublime-text
- /debian
- /nixos
- /react-native
- /agda
- /kubuntu
- /arch-linux
- /revery
- /django
- /ubuntu
- /spring
- /manjaro
- /diversity
- /nodejs
- /lua
- /c
- /slackware
- /julia
- /markdown