 
  		        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
                         
                      
                       
          
                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
 
          
                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
 
          
                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
 
          
                In general, the book isn’t yet updated for Phoenix version 1.6. On page 18 of the book, the authors indicate that an auto generated of ro...
              
            
            
          
              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
 
          
                On page 78 the following code appears: 
<%= link_to ‘Destroy’, product, 
class: ‘hover:underline’, 
method: :delete, 
data: { confirm...
              
            
            
          
              New
 
          
                It seems the second code snippet is missing the code to set the current_user: 
current_user: Accounts.get_user_by_session_token(session["...
              
            
            
          
              New
 
          
                Hi, I’ve got a question about the implementation of PubSub when using a Phoenix.Socket.Transport behaviour rather than channels. 
Before ...
              
            
            
          
              New
 
          
                I just bought this book to learn about Android development, and I’m already running into a major issue in Ch. 1, p. 20:  “Update activity...
              
            
            
          
              New
Other popular topics
                         
                      
                       
          
                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
 
          
                Curious to know which languages and frameworks you’re all thinking about learning next :upside_down_face: 
Perhaps if there’s enough peop...
              
            
            
          
              New
 
          
                If you are experiencing Rails console using 100% CPU on your dev machine, then updating your development and test gems might fix the issu...
              
            
            
          
              New
 
          
                Use WebRTC to build web applications that stream media and data in real time directly from one user to another, all in the browser.
  
...
              
            
            
              
          
              New
 
          
                Saw this on TikTok of all places! :lol: 
Anyone heard of them before? 
  
    
  
Lite:
              
            
            
          
              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
 
          
                zig/http.zig at 7cf2cbb33ef34c1d211135f56d30fe23b6cacd42 · ziglang/zig. 
General-purpose programming language and toolchain for maintaini...
              
            
            
              
          
              New
 
          
                Get the comprehensive, insider information you need for Rails 8 with the new edition of this award-winning classic.
  
Sam Ruby @rubys
...
              
            
            
              
          
              New
 
          
                Node.js v22.14.0 has been released. 
Link: Release 2025-02-11, Version 22.14.0 'Jod' (LTS), @aduh95 · nodejs/node · GitHub
              
            
            
              
          
              New
Categories:
Sub Categories:
Popular Portals
- /elixir
- /rust
- /ruby
- /wasm
- /erlang
- /phoenix
- /keyboards
- /python
- /rails
- /js
- /security
- /go
- /swift
- /vim
- /clojure
- /emacs
- /haskell
- /java
- /svelte
- /onivim
- /typescript
- /kotlin
- /crystal
- /c-plus-plus
- /tailwind
- /react
- /gleam
- /ocaml
- /elm
- /flutter
- /vscode
- /ash
- /opensuse
- /html
- /centos
- /php
- /deepseek
- /zig
- /scala
- /lisp
- /sublime-text
- /textmate
- /react-native
- /nixos
- /debian
- /agda
- /kubuntu
- /arch-linux
- /django
- /revery
- /ubuntu
- /deno
- /spring
- /nodejs
- /manjaro
- /diversity
- /lua
- /julia
- /c
- /slackware
 
    





