Skip to content

Commit 37f0082

Browse files
feat: migrate from Java 9 to Java 11
- Upgrade maven-compiler-plugin 3.1 → 3.11.0, use <release>11</release> - Upgrade JUnit 4.11 → 4.13.2 (scoped to test) - Upgrade JMH 1.17.4 → 1.37 - Add maven-surefire-plugin 3.2.5, maven-failsafe-plugin 3.2.5 - Add maven-enforcer-plugin 3.5.0 requiring Java [11,) - Move ReadPositiveIntParam.java from src/main to src/test - Add .gitignore exception for .github directory - Add 6 integration test files covering chapters 1, 4, 5, 10, 11, 12 - Add GitHub Actions CI workflow (.github/workflows/ci.yml) - Add MIGRATION_NOTES.md documenting all changes - Update README.md with JDK 11 requirement Co-Authored-By: Lukas Burger <lukaskburger@gmail.com>
1 parent 4786c46 commit 37f0082

12 files changed

Lines changed: 673 additions & 23 deletions

File tree

.github/workflows/ci.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ master, main ]
6+
pull_request:
7+
branches: [ master, main ]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Set up JDK 11
17+
uses: actions/setup-java@v4
18+
with:
19+
java-version: '11'
20+
distribution: 'temurin'
21+
cache: maven
22+
23+
- name: Compile
24+
run: mvn -B clean compile
25+
26+
- name: Test
27+
run: mvn -B test

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# Eclipse, Netbeans and IntelliJ files
55
/.*
66
!.gitignore
7+
!.github
78
/nbproject
89
/*.ipr
910
/*.iws

MIGRATION_NOTES.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Migration Notes: Java 9 → Java 11
2+
3+
## Java Version Change
4+
5+
- **From**: Java 9 (source/target 1.9)
6+
- **To**: Java 11 (using `<release>11</release>`)
7+
- The `<release>` flag replaces the legacy `<source>`/`<target>` configuration and provides stronger cross-compilation guarantees.
8+
9+
## Plugin Upgrades
10+
11+
| Plugin | Old Version | New Version | Notes |
12+
|--------|-------------|-------------|-------|
13+
| maven-compiler-plugin | 3.1 | 3.11.0 | Switched from source/target to release flag |
14+
| maven-surefire-plugin | (none) | 3.2.5 | Added for test execution |
15+
| maven-failsafe-plugin | (none) | 3.2.5 | Added for integration test support |
16+
| maven-enforcer-plugin | (none) | 3.5.0 | Added to enforce Java 11+ at build time |
17+
| maven-shade-plugin | (unchanged) | (unchanged) | Retained for JMH benchmark packaging |
18+
19+
## Dependency Upgrades
20+
21+
| Dependency | Old Version | New Version | Notes |
22+
|------------|-------------|-------------|-------|
23+
| JUnit | 4.11 | 4.13.2 | Latest JUnit 4.x; added `<scope>test</scope>` |
24+
| JMH (jmh-core) | 1.17.4 | 1.37 | Java 11 compatible |
25+
| JMH (jmh-generator-annprocess) | 1.17.4 | 1.37 | Java 11 compatible |
26+
27+
## Code Fixes Required
28+
29+
Minimal changes were needed:
30+
31+
- **Moved `ReadPositiveIntParam.java`** from `src/main/java` to `src/test/java` — this file contained JUnit `@Test` annotations but was incorrectly placed in the main source tree. With JUnit correctly scoped to `test`, it must reside under `src/test/java`.
32+
- No Nashorn JavaScript engine references found
33+
- No internal `sun.*` or `com.sun.*` API usage
34+
- No Java EE modules (removed in Java 11) were used
35+
- Deprecation warning in `Util.java` (deprecated API usage) — informational only, no breaking change
36+
37+
## New Test Coverage
38+
39+
Added integration tests covering core chapters:
40+
41+
| Test File | Chapter | Coverage |
42+
|-----------|---------|----------|
43+
| `FilteringApplesTest.java` | Chapter 1 | Lambda expressions, method references, Predicate-based filtering |
44+
| `StreamBasicsTest.java` | Chapter 4 | Stream creation, filtering, sorting, Java 7 vs Java 8 comparison |
45+
| `StreamProcessingTest.java` | Chapter 5 | Trader/Transaction queries, reduce, distinct, anyMatch |
46+
| `OptionalTest.java` | Chapter 10 | Optional creation, map, flatMap, orElse, filter, stream() |
47+
| `CompletableFutureTest.java` | Chapter 11 | supplyAsync, thenApply, thenCombine, thenCompose, exceptionally |
48+
| `DateTimeTest.java` | Chapter 12 | LocalDate, LocalTime, LocalDateTime, Duration, TemporalAdjusters, DateTimeFormatter |
49+
50+
## CI Workflow Added
51+
52+
- GitHub Actions workflow (`.github/workflows/ci.yml`)
53+
- Triggers on push/PR to master/main branches
54+
- Uses Temurin JDK 11 with Maven caching
55+
- Runs `mvn -B clean compile` and `mvn -B test`

README.md

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,31 +29,34 @@ The source code for all examples can be found in the directory [src/main/java/la
2929
* Appendix D: Lambdas and JVM bytecode
3030
We will update the repository as we update the book. Stay tuned!
3131

32-
### Make sure to have JDK8 installed
33-
The latest binary can be found here: http://www.oracle.com/technetwork/java/javase/overview/java8-2100321.html
32+
### Prerequisites
3433

35-
$ java -version
36-
37-
java version "1.8.0_05"
38-
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
39-
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)
34+
**JDK 11** or higher is required. You can use any distribution (Temurin, OpenJDK, Oracle JDK, etc.).
4035

36+
```
37+
$ java -version
38+
openjdk version "11.0.x" ...
39+
```
4140

42-
You can download a preview version here: https://jdk8.java.net/
41+
Download Temurin JDK 11: https://adoptium.net/temurin/releases/?version=11
4342

4443
### Compile/Run the examples
45-
Using maven:
4644

47-
$ mvn compile
45+
Using Maven:
4846

47+
```
48+
$ mvn clean compile
4949
$ cd target/classes
50-
5150
$ java lambdasinaction/chap1/FilteringApples
51+
```
5252

53+
Run tests:
5354

54-
Alternatively you can compile the files manually inside the directory src/main/java
55+
```
56+
$ mvn test
57+
```
5558

56-
You can also import the project in your favorite IDE:
57-
* In IntelliJ use "File->Open" menu and navigate to the folder where the project resides
58-
* In Eclipse use "File->Import->Existing Maven Projects" (also modify "Reduntant super interfaces" to report as Warnings instead of Errors
59-
* In Netbeans use "File->Open Project" menu
59+
Alternatively you can import the project in your favorite IDE:
60+
* In IntelliJ use "File->Open" menu and navigate to the folder where the project resides
61+
* In Eclipse use "File->Import->Existing Maven Projects"
62+
* In Netbeans use "File->Open Project" menu

pom.xml

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,25 @@
1010

1111
<properties>
1212
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
<maven.compiler.release>11</maven.compiler.release>
1314
</properties>
1415

1516
<dependencies>
1617
<dependency>
1718
<groupId>org.openjdk.jmh</groupId>
1819
<artifactId>jmh-core</artifactId>
19-
<version>1.17.4</version>
20+
<version>1.37</version>
2021
</dependency>
2122
<dependency>
2223
<groupId>org.openjdk.jmh</groupId>
2324
<artifactId>jmh-generator-annprocess</artifactId>
24-
<version>1.17.4</version>
25+
<version>1.37</version>
2526
</dependency>
2627
<dependency>
2728
<groupId>junit</groupId>
2829
<artifactId>junit</artifactId>
29-
<version>4.11</version>
30+
<version>4.13.2</version>
31+
<scope>test</scope>
3032
</dependency>
3133
</dependencies>
3234

@@ -35,12 +37,42 @@
3537
<plugin>
3638
<groupId>org.apache.maven.plugins</groupId>
3739
<artifactId>maven-compiler-plugin</artifactId>
38-
<version>3.1</version>
40+
<version>3.11.0</version>
3941
<configuration>
40-
<source>1.9</source>
41-
<target>1.9</target>
42+
<release>11</release>
4243
</configuration>
4344
</plugin>
45+
<plugin>
46+
<groupId>org.apache.maven.plugins</groupId>
47+
<artifactId>maven-surefire-plugin</artifactId>
48+
<version>3.2.5</version>
49+
</plugin>
50+
<plugin>
51+
<groupId>org.apache.maven.plugins</groupId>
52+
<artifactId>maven-failsafe-plugin</artifactId>
53+
<version>3.2.5</version>
54+
</plugin>
55+
<plugin>
56+
<groupId>org.apache.maven.plugins</groupId>
57+
<artifactId>maven-enforcer-plugin</artifactId>
58+
<version>3.5.0</version>
59+
<executions>
60+
<execution>
61+
<id>enforce-java</id>
62+
<goals>
63+
<goal>enforce</goal>
64+
</goals>
65+
<configuration>
66+
<rules>
67+
<requireJavaVersion>
68+
<version>[11,)</version>
69+
<message>Java 11 or higher is required to build this project.</message>
70+
</requireJavaVersion>
71+
</rules>
72+
</configuration>
73+
</execution>
74+
</executions>
75+
</plugin>
4476
<plugin>
4577
<groupId>org.apache.maven.plugins</groupId>
4678
<artifactId>maven-shade-plugin</artifactId>
@@ -63,4 +95,4 @@
6395
</plugin>
6496
</plugins>
6597
</build>
66-
</project>
98+
</project>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package lambdasinaction.chap1;
2+
3+
import lambdasinaction.chap1.FilteringApples.Apple;
4+
import org.junit.Test;
5+
6+
import java.util.Arrays;
7+
import java.util.List;
8+
9+
import static org.junit.Assert.*;
10+
11+
public class FilteringApplesTest {
12+
13+
private final List<Apple> inventory = Arrays.asList(
14+
new Apple(80, "green"),
15+
new Apple(155, "green"),
16+
new Apple(120, "red"));
17+
18+
@Test
19+
public void filterGreenApples() {
20+
List<Apple> result = FilteringApples.filterGreenApples(inventory);
21+
assertEquals(2, result.size());
22+
assertTrue(result.stream().allMatch(a -> "green".equals(a.getColor())));
23+
}
24+
25+
@Test
26+
public void filterHeavyApples() {
27+
List<Apple> result = FilteringApples.filterHeavyApples(inventory);
28+
assertEquals(1, result.size());
29+
assertTrue(result.get(0).getWeight() > 150);
30+
}
31+
32+
@Test
33+
public void filterWithMethodReference() {
34+
List<Apple> greens = FilteringApples.filterApples(inventory, FilteringApples::isGreenApple);
35+
assertEquals(2, greens.size());
36+
37+
List<Apple> heavies = FilteringApples.filterApples(inventory, FilteringApples::isHeavyApple);
38+
assertEquals(1, heavies.size());
39+
}
40+
41+
@Test
42+
public void filterWithLambda() {
43+
List<Apple> greens = FilteringApples.filterApples(inventory, a -> "green".equals(a.getColor()));
44+
assertEquals(2, greens.size());
45+
46+
List<Apple> heavies = FilteringApples.filterApples(inventory, a -> a.getWeight() > 150);
47+
assertEquals(1, heavies.size());
48+
}
49+
50+
@Test
51+
public void filterWithComplexPredicate() {
52+
List<Apple> result = FilteringApples.filterApples(inventory,
53+
a -> a.getWeight() < 80 || "brown".equals(a.getColor()));
54+
assertTrue(result.isEmpty());
55+
}
56+
57+
@Test
58+
public void appleToString() {
59+
Apple apple = new Apple(80, "green");
60+
String str = apple.toString();
61+
assertTrue(str.contains("green"));
62+
assertTrue(str.contains("80"));
63+
}
64+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package lambdasinaction.chap10;
2+
3+
import org.junit.Test;
4+
5+
import java.util.Arrays;
6+
import java.util.Optional;
7+
import java.util.Set;
8+
9+
import static org.junit.Assert.*;
10+
11+
public class OptionalTest {
12+
13+
@Test
14+
public void getCarInsuranceNameWithEmptyPerson() {
15+
OptionalMain main = new OptionalMain();
16+
String result = main.getCarInsuranceName(Optional.empty());
17+
assertEquals("Unknown", result);
18+
}
19+
20+
@Test
21+
public void optionalOfNullable() {
22+
Optional<String> opt = Optional.ofNullable(null);
23+
assertFalse(opt.isPresent());
24+
25+
Optional<String> present = Optional.ofNullable("hello");
26+
assertTrue(present.isPresent());
27+
assertEquals("hello", present.get());
28+
}
29+
30+
@Test
31+
public void optionalMap() {
32+
Optional<String> name = Optional.of("Java");
33+
Optional<Integer> len = name.map(String::length);
34+
assertEquals(Integer.valueOf(4), len.get());
35+
}
36+
37+
@Test
38+
public void optionalFlatMap() {
39+
Optional<Optional<String>> nested = Optional.of(Optional.of("nested"));
40+
Optional<String> flat = nested.flatMap(x -> x);
41+
assertEquals("nested", flat.get());
42+
}
43+
44+
@Test
45+
public void optionalOrElse() {
46+
Optional<String> empty = Optional.empty();
47+
assertEquals("default", empty.orElse("default"));
48+
49+
Optional<String> present = Optional.of("value");
50+
assertEquals("value", present.orElse("default"));
51+
}
52+
53+
@Test
54+
public void optionalFilter() {
55+
Optional<String> opt = Optional.of("hello");
56+
assertTrue(opt.filter(s -> s.startsWith("h")).isPresent());
57+
assertFalse(opt.filter(s -> s.startsWith("z")).isPresent());
58+
}
59+
60+
@Test
61+
public void optionalIfPresent() {
62+
Optional<String> opt = Optional.of("test");
63+
StringBuilder sb = new StringBuilder();
64+
opt.ifPresent(sb::append);
65+
assertEquals("test", sb.toString());
66+
}
67+
68+
@Test
69+
public void optionalStream() {
70+
Optional<String> present = Optional.of("value");
71+
long count = present.stream().count();
72+
assertEquals(1, count);
73+
74+
Optional<String> empty = Optional.empty();
75+
long emptyCount = empty.stream().count();
76+
assertEquals(0, emptyCount);
77+
}
78+
79+
@Test
80+
public void insuranceNameAccess() {
81+
Insurance insurance = new Insurance();
82+
assertNull(insurance.getName());
83+
}
84+
}

src/main/java/lambdasinaction/chap10/ReadPositiveIntParam.java renamed to src/test/java/lambdasinaction/chap10/ReadPositiveIntParam.java

File renamed without changes.

0 commit comments

Comments
 (0)