
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

This test is broken right out of the box…
— FAIL: TestAgent (7.82s)
agent_test.go:77:
Error Trace: agent_test.go:77
agent_test.go:...
New

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

Running the examples in chapter 5 c under pytest 5.4.1 causes an AttributeError: ‘module’ object has no attribute ‘config’.
In particula...
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 ProductLive.Index template calls a helper function, live_component/3, that in turn calls on the modal component. ”
Excerpt From: Br...
New

I’m not quite sure what’s going on here, but I’m unable to have to containers successfully complete the Readiness/Liveness checks. I’m im...
New

Hi,
I completed chapter 6 but am getting the following error when running:
thread 'main' panicked at 'Failed to load texture: IoError(O...
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

root_layout: {PentoWeb.LayoutView, :root},
This results in the following following error:
no “root” html template defined for PentoWeb...
New
Other popular topics

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

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

Hello everyone! This thread is to tell you about what authors from The Pragmatic Bookshelf are writing on Medium.
New

Create efficient, elegant software tests in pytest, Python's most powerful testing framework.
Brian Okken @brianokken
Edited by Kat...
New

Biggest jackpot ever apparently! :upside_down_face:
I don’t (usually) gamble/play the lottery, but working on a program to predict the...
New

Author Spotlight:
VM Brasseur
@vmbrasseur
We have a treat for you today! We turn the spotlight onto Open Source as we sit down with V...
New

Author Spotlight:
Peter Ullrich
@PJUllrich
Data is at the core of every business, but it is useless if nobody can access and analyze ...
New

Get the comprehensive, insider information you need for Rails 8 with the new edition of this award-winning classic.
Sam Ruby @rubys
...
New

This is cool!
DEEPSEEK-V3 ON M4 MAC: BLAZING FAST INFERENCE ON APPLE SILICON
We just witnessed something incredible: the largest open-s...
New

Ok, well here are some thoughts and opinions on some of the ergonomic keyboards I have, I guess like mini review of each that I use enoug...
New
Categories:
Sub Categories:
Popular Portals
- /elixir
- /rust
- /ruby
- /wasm
- /erlang
- /phoenix
- /keyboards
- /rails
- /python
- /js
- /security
- /go
- /swift
- /vim
- /clojure
- /emacs
- /haskell
- /java
- /onivim
- /typescript
- /svelte
- /crystal
- /c-plus-plus
- /kotlin
- /tailwind
- /react
- /gleam
- /ocaml
- /flutter
- /elm
- /vscode
- /ash
- /opensuse
- /html
- /centos
- /php
- /deepseek
- /zig
- /scala
- /textmate
- /lisp
- /sublime-text
- /nixos
- /debian
- /react-native
- /agda
- /kubuntu
- /arch-linux
- /django
- /revery
- /ubuntu
- /manjaro
- /spring
- /nodejs
- /diversity
- /lua
- /deno
- /julia
- /slackware
- /c