├── settings.gradle ├── FunctionalModernJava.pdf ├── src ├── main │ ├── java │ │ ├── got │ │ │ ├── Title.java │ │ │ ├── MemberDAO.java │ │ │ ├── House.java │ │ │ ├── Member.java │ │ │ └── InMemoryMemberDAO.java │ │ ├── interfaces │ │ │ ├── Animal.java │ │ │ ├── PrivateDemo.java │ │ │ ├── Bird.java │ │ │ ├── Horse.java │ │ │ ├── Company.java │ │ │ ├── Pegasus.java │ │ │ ├── Employee.java │ │ │ ├── MyCompany.java │ │ │ └── SumNumbers.java │ │ ├── lazy │ │ │ ├── OptionalExceptionDemo.java │ │ │ └── LazyStreams.java │ │ ├── eam │ │ │ ├── before │ │ │ │ ├── UseResource.java │ │ │ │ └── Resource.java │ │ │ └── after │ │ │ │ ├── UseResource.java │ │ │ │ └── Resource.java │ │ ├── lambdas │ │ │ ├── Runner.java │ │ │ ├── RunnableDemo.java │ │ │ ├── Person.java │ │ │ ├── UsePerson.java │ │ │ ├── MapDemo.java │ │ │ └── FilenameFilterDemo.java │ │ ├── primes │ │ │ ├── after │ │ │ │ ├── PrimeCalculator.java │ │ │ │ └── SumSqrtPrimes.java │ │ │ └── before │ │ │ │ ├── PrimeCalculator.java │ │ │ │ └── SumSqrtPrimes.java │ │ ├── streams │ │ │ ├── Order.java │ │ │ ├── Customer.java │ │ │ ├── SumBigDecimals.java │ │ │ └── FlatMapDemo.java │ │ ├── IterateDemo.java │ │ ├── SummarizingDemo.java │ │ ├── generics │ │ │ └── SafeVaragsDemo.java │ │ ├── FinderDemo.java │ │ ├── optional │ │ │ ├── ProductDAO.java │ │ │ └── Product.java │ │ ├── refactoring │ │ │ ├── after │ │ │ │ └── LoopsSortsAndIfs.java │ │ │ └── before │ │ │ │ └── LoopsSortsAndIfs.java │ │ ├── RandomDemo.java │ │ ├── dao │ │ │ └── Employee.java │ │ ├── http │ │ │ ├── AstroClient.java │ │ │ ├── JokeResponse.java │ │ │ └── JokeClient.java │ │ ├── datetime │ │ │ └── AntarcticaTimeZones.java │ │ ├── OptionalDemo.java │ │ ├── CollectorsDemo.java │ │ ├── sorting │ │ │ ├── Golfer.java │ │ │ ├── SortGolfers.java │ │ │ └── SortStrings.java │ │ ├── io │ │ │ └── ProcessDictionary.java │ │ └── fileio │ │ │ └── ProcessDictionary.java │ └── resources │ │ └── dict │ │ ├── README │ │ ├── connectives │ │ └── propernames └── test │ └── java │ ├── http │ ├── AstroClientTest.java │ └── JokeClientTest.java │ ├── interfaces │ ├── SumNumbersTest.java │ ├── PrivateDemoTest.java │ └── CompanyEmployeeTest.java │ ├── lambdas │ ├── BinaryOperatorTest.java │ └── FunctionalInterfacesTest.java │ ├── streams │ ├── SumEvens.java │ ├── SumBigDecimalsTest.java │ └── StringExercises.java │ ├── optional │ └── ProductDAOTest.java │ ├── generics │ └── SafeVaragsDemoTest.java │ ├── collections │ ├── ImmutableCollectionsTest.java │ └── ImmutableMapTest.java │ ├── lvti │ └── VarTypeTest.java │ └── got │ └── MemberDAOTests.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .claude └── settings.local.json ├── .github ├── dependabot.yml └── workflows │ └── gradle.yml ├── .gitignore ├── topics.md ├── README.md ├── gradlew.bat ├── CLAUDE.md └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'functional_modern_java' 2 | 3 | -------------------------------------------------------------------------------- /FunctionalModernJava.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kousen/functional_modern_java/HEAD/FunctionalModernJava.pdf -------------------------------------------------------------------------------- /src/main/java/got/Title.java: -------------------------------------------------------------------------------- 1 | package got; 2 | 3 | public enum Title { 4 | SIR, LORD, LADY, KING, QUEEN 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/interfaces/Animal.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public interface Animal { 4 | String speak(); 5 | } 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kousen/functional_modern_java/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/interfaces/PrivateDemo.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public class PrivateDemo implements SumNumbers { 4 | } 5 | -------------------------------------------------------------------------------- /.claude/settings.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "permissions": { 3 | "allow": [ 4 | "Bash(./gradlew:*)", 5 | "Bash(git add:*)" 6 | ], 7 | "deny": [] 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/java/interfaces/Bird.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public interface Bird extends Animal { 4 | default String speak() { 5 | return "chirp"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/lazy/OptionalExceptionDemo.java: -------------------------------------------------------------------------------- 1 | package lazy; 2 | 3 | public class OptionalExceptionDemo { 4 | public static void main(String[] args) { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/interfaces/Horse.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public interface Horse extends Animal { 4 | default String speak() { 5 | return "neigh"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/interfaces/Company.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public interface Company { 4 | default String getName() { 5 | return "Initech"; 6 | } 7 | 8 | // String getName(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/interfaces/Pegasus.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public class Pegasus implements Horse, Bird { 4 | @Override 5 | public String speak() { 6 | return Horse.super.speak() + " " + Bird.super.speak(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/eam/before/UseResource.java: -------------------------------------------------------------------------------- 1 | package eam.before; 2 | 3 | public class UseResource { 4 | public static void main(String[] args) { 5 | Resource resource = new Resource(); 6 | resource.op1(); 7 | resource.op2(); 8 | // cleanup? 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gradle 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: org.junit.jupiter:junit-jupiter 11 | versions: 12 | - 5.7.1 13 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /src/main/java/interfaces/Employee.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public interface Employee { 4 | String getFirst(); 5 | 6 | String getLast(); 7 | 8 | void doWork(); 9 | 10 | default String getName() { 11 | return String.format("%s %s", getFirst(), getLast()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/lambdas/Runner.java: -------------------------------------------------------------------------------- 1 | package lambdas; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | public class Runner { 6 | public void invoke(Runnable r) { 7 | r.run(); 8 | } 9 | 10 | public T invoke(Callable c) throws Exception { 11 | return c.call(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/http/AstroClientTest.java: -------------------------------------------------------------------------------- 1 | package http; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | class AstroClientTest { 6 | private final AstroClient client = new AstroClient(); 7 | 8 | @Test 9 | void checkJsonOutput() { 10 | System.out.println(client.getJsonResponse()); 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/java/got/MemberDAO.java: -------------------------------------------------------------------------------- 1 | package got; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | import java.util.Optional; 6 | 7 | public interface MemberDAO { 8 | Member findById(Long id); 9 | Optional findByName(String name); 10 | List findAllByHouse(House house); 11 | Collection getAll(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/interfaces/MyCompany.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | public class MyCompany implements Company { 4 | 5 | @Override 6 | public String getName() { 7 | return "Yoyodyne Propulsion Systems"; 8 | } 9 | 10 | public static void main(String[] args) { 11 | MyCompany co = new MyCompany(); 12 | System.out.println(co.getName()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/primes/after/PrimeCalculator.java: -------------------------------------------------------------------------------- 1 | package primes.after; 2 | 3 | import java.util.stream.IntStream; 4 | 5 | public class PrimeCalculator { 6 | public static boolean isPrime(int number) { 7 | int max = (int) (Math.sqrt(number) + 1); 8 | return number > 1 && 9 | IntStream.range(2, max) 10 | .noneMatch(index -> number % index == 0); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/eam/after/UseResource.java: -------------------------------------------------------------------------------- 1 | package eam.after; 2 | 3 | public class UseResource { 4 | public static void main(String[] args) { 5 | // Resource r = new Resource(); 6 | // try { 7 | // r.op1(); 8 | // r.op2(); 9 | // } finally { 10 | // r.close(); 11 | // } 12 | 13 | Resource.use(resource -> { 14 | resource.op1(); 15 | resource.op2(); 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/eam/before/Resource.java: -------------------------------------------------------------------------------- 1 | package eam.before; 2 | 3 | public class Resource { 4 | public Resource() { 5 | System.out.println("Instance created"); 6 | } 7 | 8 | public void op1() { 9 | System.out.println("op1 called...."); 10 | } 11 | 12 | public void op2() { 13 | System.out.println("op2 called..."); 14 | } 15 | 16 | protected void finalize() { 17 | System.out.println("do any cleanup here..."); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/primes/before/PrimeCalculator.java: -------------------------------------------------------------------------------- 1 | package primes.before; 2 | 3 | public class PrimeCalculator { 4 | public static boolean isPrime(int number) { 5 | int max = (int) (Math.sqrt(number) + 1); 6 | 7 | boolean prime = true; 8 | for (int index = 2; index <= max; index++) { 9 | if (number % index == 0) { 10 | prime = false; 11 | break; 12 | } 13 | } 14 | return prime; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/streams/Order.java: -------------------------------------------------------------------------------- 1 | package streams; 2 | 3 | public class Order { 4 | private int id; 5 | 6 | public Order(int id) { 7 | this.id = id; 8 | } 9 | 10 | public void setId(int id) { 11 | this.id = id; 12 | } 13 | 14 | public int getId() { 15 | return id; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return "Order{" + 21 | "id=" + id + 22 | '}'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/IterateDemo.java: -------------------------------------------------------------------------------- 1 | import java.time.LocalDate; 2 | import java.util.Optional; 3 | import java.util.stream.Stream; 4 | 5 | public class IterateDemo { 6 | public static void main(String[] args) { 7 | Stream.iterate(100, n -> n + 2) 8 | .limit(20) 9 | .forEach(System.out::println); 10 | 11 | Stream.iterate(LocalDate.now(), date -> date.plusMonths(1)) 12 | .limit(12) 13 | .forEach(System.out::println); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/interfaces/SumNumbersTest.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class SumNumbersTest { 8 | private final SumNumbers demo = new PrivateDemo(); 9 | 10 | @Test 11 | public void addEvens() { 12 | assertEquals(2 + 4 + 6, demo.addEvens(1, 2, 3, 4, 5, 6)); 13 | } 14 | 15 | @Test 16 | public void addOdds() { 17 | assertEquals(1 + 3 + 5, demo.addOdds(1, 2, 3, 4, 5, 6)); 18 | } 19 | } -------------------------------------------------------------------------------- /src/test/java/interfaces/PrivateDemoTest.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class PrivateDemoTest { 8 | private final PrivateDemo demo = new PrivateDemo(); 9 | 10 | @Test 11 | public void addEvens() { 12 | int sum = demo.addEvens(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 13 | assertEquals(30, sum); 14 | } 15 | 16 | @Test 17 | public void addOdds() { 18 | int sum = demo.addOdds(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 19 | assertEquals(25, sum); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/primes/before/SumSqrtPrimes.java: -------------------------------------------------------------------------------- 1 | package primes.before; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class SumSqrtPrimes { 7 | public static void main(String[] args) { 8 | List sqrtOfFirst100Primes = new ArrayList<>(); 9 | 10 | int index = 2; 11 | while (sqrtOfFirst100Primes.size() < 100) { 12 | if (PrimeCalculator.isPrime(index)) { 13 | sqrtOfFirst100Primes.add(Math.sqrt(index)); 14 | } 15 | index++; 16 | } 17 | 18 | System.out.println(sqrtOfFirst100Primes); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/primes/after/SumSqrtPrimes.java: -------------------------------------------------------------------------------- 1 | package primes.after; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | import java.util.stream.Stream; 6 | 7 | public class SumSqrtPrimes { 8 | public static void main(String[] args) { 9 | 10 | List sqrtOfFirst100Primes = 11 | Stream.iterate(2, e -> e + 1) 12 | .filter(PrimeCalculator::isPrime) 13 | .limit(100) 14 | .map(Math::sqrt) 15 | .collect(Collectors.toList()); 16 | System.out.println(sqrtOfFirst100Primes); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/interfaces/CompanyEmployeeTest.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | // Create a class called CompanyEmployee that implements both 6 | // the Company and Employee interfaces 7 | // Implement the necessary methods 8 | // Give the class a two-arg constructor that takes first and last name 9 | // Implement the getName method so that the test below passes 10 | public class CompanyEmployeeTest { 11 | 12 | @Test 13 | public void getName() { 14 | // CompanyEmployee emp = new CompanyEmployee("Peter", "Gibbons"); 15 | // assertEquals("Peter Gibbons works for Initech", emp.getName()); 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/java/SummarizingDemo.java: -------------------------------------------------------------------------------- 1 | import java.util.DoubleSummaryStatistics; 2 | import java.util.stream.DoubleStream; 3 | 4 | public class SummarizingDemo { 5 | public static void main(String[] args) { 6 | DoubleSummaryStatistics stats = DoubleStream.generate(Math::random) 7 | .limit(1_000_000) 8 | .summaryStatistics(); 9 | 10 | System.out.println(stats); 11 | System.out.println(stats.getCount()); 12 | System.out.println(stats.getMin()); 13 | System.out.println(stats.getAverage()); 14 | System.out.println(stats.getMax()); 15 | System.out.println(stats.getSum()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/generics/SafeVaragsDemo.java: -------------------------------------------------------------------------------- 1 | package generics; 2 | 3 | import java.time.LocalDate; 4 | 5 | @SuppressWarnings("UnusedReturnValue") 6 | public class SafeVaragsDemo { 7 | 8 | public String[] replaceFirstStringWithDate(LocalDate date, String... strings) { 9 | strings[0] = date.toString(); 10 | return strings; 11 | } 12 | 13 | @SafeVarargs // can only be applied to final methods 14 | public final T[] replaceFirstValueInArray(T value, T... array) { 15 | // Compiles because of type erasure 16 | // But "possible heap pollution from parameterized vararg type" 17 | array[0] = value; 18 | return array; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/interfaces/SumNumbers.java: -------------------------------------------------------------------------------- 1 | package interfaces; 2 | 3 | import java.util.function.IntPredicate; 4 | import java.util.stream.IntStream; 5 | 6 | public interface SumNumbers { 7 | IntPredicate EVENS = n -> n % 2 == 0; 8 | 9 | default int addEvens(int... nums) { 10 | // return add(n -> n % 2 == 0, nums); 11 | return add(EVENS, nums); 12 | } 13 | 14 | default int addOdds(int... nums) { 15 | return add(n -> n % 2 != 0, nums); 16 | } 17 | 18 | private int add(IntPredicate predicate, int... nums) { 19 | return IntStream.of(nums) 20 | .filter(predicate) 21 | .sum(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/streams/Customer.java: -------------------------------------------------------------------------------- 1 | package streams; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Customer { 7 | private final String name; 8 | private final List orders = new ArrayList<>(); 9 | 10 | public Customer(String name) { 11 | this.name = name; 12 | } 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public Customer addOrder(Order order) { 19 | orders.add(order); 20 | return this; 21 | } 22 | 23 | public List getOrders() { 24 | return orders; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return name; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/FinderDemo.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.HashSet; 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | public class FinderDemo { 7 | public static void main(String[] args) { 8 | List strings = Arrays.asList("this", "is", "a", "list", "of", "strings"); 9 | HashSet stringSet = new HashSet<>(strings); 10 | 11 | Optional first = strings.stream() 12 | .filter(s -> { 13 | System.out.println(Thread.currentThread().getName() + " with " + s); 14 | return s.length() == 2; 15 | }) 16 | .findFirst(); 17 | System.out.println(first); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/lambdas/BinaryOperatorTest.java: -------------------------------------------------------------------------------- 1 | package lambdas; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | import java.util.Optional; 8 | import java.util.function.BinaryOperator; 9 | 10 | public class BinaryOperatorTest { 11 | @Test 12 | public void concatAsBinaryOperator() { 13 | BinaryOperator concat = String::concat; 14 | concat = (s, str) -> s.concat(str); 15 | 16 | List strings = Arrays.asList("this", "is", "a", "list", "of", "strings"); 17 | Optional str = strings.stream() 18 | //.filter(s -> false) 19 | .reduce(concat); 20 | System.out.println(str.orElse("")); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/lambdas/RunnableDemo.java: -------------------------------------------------------------------------------- 1 | package lambdas; 2 | 3 | public class RunnableDemo { 4 | public static void main(String[] args) { 5 | // Java 7 syntax 6 | new Thread(new Runnable() { 7 | @Override 8 | public void run() { 9 | System.out.println("Inside an anonymous inner class"); 10 | } 11 | }).start(); 12 | 13 | new Thread(() -> System.out.println("Inside expression lambda")).start(); 14 | 15 | new Thread(() -> { 16 | System.out.println("Inside block lambda"); 17 | }).start(); 18 | 19 | Runnable runnable = () -> System.out.println("Assigned to a variable"); 20 | new Thread(runnable).start(); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Gradle 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle 3 | 4 | name: Java CI with Gradle 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up JDK 21 20 | uses: actions/setup-java@v4 21 | with: 22 | java-version: 21 23 | distribution: 'temurin' 24 | - name: Grant execute permission for gradlew 25 | run: chmod +x gradlew 26 | - name: Build with Gradle 27 | run: ./gradlew build 28 | -------------------------------------------------------------------------------- /src/main/java/got/House.java: -------------------------------------------------------------------------------- 1 | package got; 2 | 3 | public class House { 4 | private String name; 5 | 6 | public House(String name) { 7 | this.name = name; 8 | } 9 | 10 | public String getName() { 11 | return name; 12 | } 13 | 14 | public void setName(String name) { 15 | this.name = name; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return name; 21 | } 22 | 23 | @Override 24 | public boolean equals(Object o) { 25 | if (this == o) return true; 26 | if (o == null || getClass() != o.getClass()) return false; 27 | 28 | House house = (House) o; 29 | 30 | return name.equals(house.name); 31 | 32 | } 33 | 34 | @Override 35 | public int hashCode() { 36 | return name.hashCode(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/optional/ProductDAO.java: -------------------------------------------------------------------------------- 1 | package optional; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Optional; 6 | 7 | public class ProductDAO { 8 | private static final Map products = new HashMap<>(); 9 | 10 | static { 11 | products.put(1, new Product(1, "Football", 12.99)); 12 | products.put(2, new Product(2, "Basketball", 15.99)); 13 | products.put(3, new Product(3, "Baseball", 5.99)); 14 | } 15 | 16 | public Optional findById(Integer id) { 17 | return Optional.ofNullable(products.get(id)); 18 | } 19 | 20 | 21 | public Product getProductById(Integer id) { 22 | Optional optional = findById(id); 23 | // Create default product only if no product with that id 24 | return optional.orElseGet(() -> new Product(999, "No name", 0.00)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/lambdas/Person.java: -------------------------------------------------------------------------------- 1 | package lambdas; 2 | 3 | import java.util.Objects; 4 | 5 | public class Person { 6 | private String name; 7 | 8 | public Person() {} 9 | 10 | public Person(String name) { 11 | this.name = name; 12 | } 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | 22 | @Override 23 | public boolean equals(Object o) { 24 | if (this == o) return true; 25 | if (!(o instanceof Person)) return false; 26 | 27 | Person person = (Person) o; 28 | 29 | return Objects.equals(name, person.name); 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | return Objects.hashCode(name); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return String.format("Person(%s)", name); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/refactoring/after/LoopsSortsAndIfs.java: -------------------------------------------------------------------------------- 1 | package refactoring.after; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.Comparator; 6 | import java.util.List; 7 | 8 | public class LoopsSortsAndIfs { 9 | public static void main(String[] args) { 10 | String[] strings = "this is an array of strings".split(" "); 11 | 12 | List evenLengths = new ArrayList<>(); 13 | for (String s : strings) { 14 | if (s.length() % 2 == 0) { 15 | evenLengths.add(s); 16 | } 17 | } 18 | 19 | Collections.sort(evenLengths, new Comparator() { 20 | @Override 21 | public int compare(String s1, String s2) { 22 | return s1.length() - s2.length(); 23 | } 24 | }); 25 | 26 | for (String s : evenLengths) { 27 | System.out.println(s); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/refactoring/before/LoopsSortsAndIfs.java: -------------------------------------------------------------------------------- 1 | package refactoring.before; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.Comparator; 6 | import java.util.List; 7 | 8 | public class LoopsSortsAndIfs { 9 | public static void main(String[] args) { 10 | String[] strings = "this is an array of strings".split(" "); 11 | 12 | List evenLengths = new ArrayList<>(); 13 | for (String s : strings) { 14 | if (s.length() % 2 == 0) { 15 | evenLengths.add(s); 16 | } 17 | } 18 | 19 | Collections.sort(evenLengths, new Comparator() { 20 | @Override 21 | public int compare(String s1, String s2) { 22 | return s1.length() - s2.length(); 23 | } 24 | }); 25 | 26 | for (String s : evenLengths) { 27 | System.out.println(s); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/streams/SumEvens.java: -------------------------------------------------------------------------------- 1 | package streams; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | import java.util.function.IntPredicate; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | public class SumEvens { 12 | private static final IntPredicate EVENS = n -> n % 2 == 0; 13 | private static final IntPredicate ODDS = n -> n % 2 != 0; 14 | 15 | @Test 16 | public void addEvenElements() { 17 | List integers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5); 18 | int sum = 0; 19 | for (int n : integers) { 20 | if (n % 2 == 0) { 21 | sum += n; 22 | } 23 | } 24 | assertEquals(12, sum); 25 | } 26 | 27 | @Test 28 | public void addEvenElementsUsingStreams() { 29 | } 30 | 31 | @Test 32 | public void addOddElementsUsingStreams() { 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/RandomDemo.java: -------------------------------------------------------------------------------- 1 | import java.util.OptionalInt; 2 | import java.util.Random; 3 | import java.util.stream.IntStream; 4 | 5 | public class RandomDemo { 6 | public static void main(String[] args) { 7 | Random r = new Random(); 8 | int sum = IntStream.generate(() -> r.nextInt(10)) 9 | .limit(10) 10 | .map(n -> { 11 | System.out.println("n = " + n); 12 | return n; 13 | }) 14 | .filter(n -> n % 2 == 0) // only even numbers 15 | .peek(System.out::println) 16 | .map(n -> n * 2) 17 | .sum(); 18 | System.out.println(sum); 19 | 20 | System.out.println("Filtering integers:"); 21 | OptionalInt first = IntStream.generate(() -> r.nextInt(10)) 22 | .peek(System.out::println) 23 | .filter(n -> n > 7) 24 | .findFirst(); 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/dao/Employee.java: -------------------------------------------------------------------------------- 1 | package dao; 2 | 3 | import java.util.Optional; 4 | 5 | public class Employee { 6 | private int id; 7 | private String first; 8 | private String middleInitial; 9 | private String last; 10 | 11 | public int getId() { 12 | return id; 13 | } 14 | 15 | public void setId(int id) { 16 | this.id = id; 17 | } 18 | 19 | public String getFirst() { 20 | return first; 21 | } 22 | 23 | public void setFirst(String first) { 24 | this.first = first; 25 | } 26 | 27 | public Optional getMiddleInitial() { 28 | return Optional.ofNullable(middleInitial); 29 | } 30 | 31 | public void setMiddleInitial(String middleInitial) { 32 | this.middleInitial = middleInitial; 33 | } 34 | 35 | public String getLast() { 36 | return last; 37 | } 38 | 39 | public void setLast(String last) { 40 | this.last = last; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/lambdas/UsePerson.java: -------------------------------------------------------------------------------- 1 | package lambdas; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | public class UsePerson { 8 | @SuppressWarnings({"UnusedAssignment", "Convert2MethodRef"}) 9 | public static void main(String[] args) { 10 | List names = Arrays.asList("John", "Paul", "George", "Ringo"); 11 | 12 | List people = names.stream() // Stream 13 | .map(name -> new Person(name)) // Stream 14 | .collect(Collectors.toList()); // Converts Stream to List 15 | 16 | people = names.stream() 17 | .map(Person::new) 18 | .collect(Collectors.toList()); 19 | 20 | System.out.println(people); 21 | 22 | Person[] peopleArray = names.stream() 23 | .map(Person::new) 24 | .toArray(Person[]::new); 25 | 26 | System.out.println(Arrays.toString(peopleArray)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | *.class 4 | .classpath 5 | .project 6 | .settings/ 7 | 8 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 9 | hs_err_pid* 10 | replay_pid* 11 | 12 | # Gradle 13 | .gradle/ 14 | build/ 15 | /bin/ 16 | !gradle-wrapper.jar 17 | !gradle/wrapper/gradle-wrapper.properties 18 | 19 | # IDEs 20 | .idea/ 21 | *.iml 22 | *.ipr 23 | .vscode/ 24 | *.swp 25 | *.swo 26 | *~ 27 | 28 | # macOS 29 | .DS_Store 30 | .DS_Store? 31 | ._* 32 | .Spotlight-V100 33 | .Trashes 34 | ehthumbs.db 35 | Thumbs.db 36 | 37 | # Windows 38 | *.tmp 39 | *.temp 40 | 41 | # Linux 42 | *~ 43 | 44 | # Logs 45 | *.log 46 | logs/ 47 | 48 | # Test reports and coverage 49 | **/reports/ 50 | **/test-results/ 51 | .jacoco/ 52 | *.exec 53 | 54 | # Temporary files 55 | *.tmp 56 | *.bak 57 | *.swp 58 | *~.nib 59 | local.properties 60 | 61 | # Package Files 62 | *.jar 63 | *.war 64 | *.nar 65 | *.ear 66 | *.zip 67 | *.tar.gz 68 | *.rar 69 | 70 | # Application specific 71 | out/ 72 | target/ -------------------------------------------------------------------------------- /src/test/java/streams/SumBigDecimalsTest.java: -------------------------------------------------------------------------------- 1 | package streams; 2 | 3 | import org.junit.jupiter.api.Disabled; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.math.BigDecimal; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | public class SumBigDecimalsTest { 11 | private final SumBigDecimals summer = new SumBigDecimals(); 12 | 13 | @Test 14 | public void sumFirstN_usingReduce() { 15 | BigDecimal answer = summer.sumFirstN_usingReduce(10); 16 | assertEquals(new BigDecimal("55"), answer); 17 | } 18 | 19 | @Test @Disabled("disable until demo") 20 | public void sumFirstNDoubledValues() { 21 | BigDecimal answer = summer.sumDoubles(10); 22 | 23 | // Used to show how reduce method without identity can give error 24 | assertEquals(new BigDecimal("110"), answer); 25 | } 26 | 27 | @Test 28 | public void sumFirstNDoubledValuesInitialized() { 29 | BigDecimal answer = summer.sumDoublesInitialized(10); 30 | assertEquals(new BigDecimal("110"), answer); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/test/java/optional/ProductDAOTest.java: -------------------------------------------------------------------------------- 1 | package optional; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Optional; 6 | import java.util.stream.IntStream; 7 | 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | public class ProductDAOTest { 11 | private final ProductDAO dao = new ProductDAO(); 12 | 13 | @Test 14 | public void findById_exists() { 15 | IntStream.rangeClosed(1, 3) 16 | .forEach(id -> assertTrue(dao.findById(id).isPresent())); 17 | } 18 | 19 | @Test 20 | public void findById_doesNotExist() { 21 | Optional optionalProduct = dao.findById(999); 22 | assertFalse(optionalProduct.isPresent()); 23 | } 24 | 25 | @Test 26 | public void getProductById_exists() { 27 | Product product = dao.getProductById(1); 28 | assertEquals(1, product.getId().intValue()); 29 | } 30 | 31 | @Test 32 | public void getProductById_doesNotExist() { 33 | Product product = dao.getProductById(999); 34 | assertEquals(999, product.getId().intValue()); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/lambdas/MapDemo.java: -------------------------------------------------------------------------------- 1 | package lambdas; 2 | 3 | import java.util.Comparator; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.function.BiFunction; 7 | 8 | public class MapDemo { 9 | public static void main(String[] args) { 10 | Map map = new HashMap<>(); 11 | map.put("c", 2); 12 | map.put("a", 1); 13 | map.put("d", 3); 14 | map.put("b", 2); 15 | 16 | map.computeIfAbsent("e", String::length); 17 | map.computeIfAbsent("b", String::length); 18 | map.computeIfPresent("b", (k, v) -> { 19 | System.out.printf("k = %s,v = %d%n", k, v); 20 | return v * 2; 21 | }); 22 | map.forEach((k,v) -> System.out.println(k + " maps to " + v)); 23 | 24 | map.entrySet().stream() 25 | .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())) 26 | .forEach(System.out::println); 27 | 28 | map.entrySet().stream() 29 | .sorted(Map.Entry.comparingByValue()) 30 | .forEach(System.out::println); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/http/AstroClient.java: -------------------------------------------------------------------------------- 1 | package http; 2 | 3 | import java.io.IOException; 4 | import java.net.URI; 5 | import java.net.http.HttpClient; 6 | import java.net.http.HttpRequest; 7 | import java.net.http.HttpResponse; 8 | import java.time.Duration; 9 | 10 | public class AstroClient { 11 | 12 | public String getJsonResponse() { 13 | HttpClient client = HttpClient.newBuilder() 14 | .connectTimeout(Duration.ofSeconds(2)) 15 | .build(); 16 | 17 | HttpRequest request = HttpRequest.newBuilder() 18 | .uri(URI.create("http://api.open-notify.org/astros.json")) 19 | .GET() 20 | .build(); 21 | 22 | try { 23 | HttpResponse response = 24 | client.send(request, HttpResponse.BodyHandlers.ofString()); 25 | System.out.println(response.statusCode()); 26 | System.out.println(response.headers()); 27 | return response.body(); 28 | } catch (IOException | InterruptedException e) { 29 | e.printStackTrace(); 30 | } 31 | return ""; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/eam/after/Resource.java: -------------------------------------------------------------------------------- 1 | package eam.after; 2 | 3 | import java.util.function.Consumer; 4 | import java.util.function.Function; 5 | 6 | public class Resource { 7 | private Resource() { 8 | System.out.println("Instance created"); 9 | } 10 | 11 | public void op1() { 12 | System.out.println("op1 called...."); 13 | } 14 | 15 | public void op2() { 16 | System.out.println("op2 called..."); 17 | } 18 | 19 | private void close() { 20 | System.out.println("do any cleanup here..."); 21 | } 22 | 23 | public static void use(Consumer consume) { 24 | Resource resource = new Resource(); 25 | try { 26 | consume.accept(resource); 27 | } finally { 28 | resource.close(); 29 | } 30 | } 31 | 32 | public static R useWithReturn(Function function) { 33 | R result = null; 34 | Resource resource = new Resource(); 35 | try { 36 | result = function.apply(resource); 37 | } finally { 38 | resource.close(); 39 | } 40 | return result; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/datetime/AntarcticaTimeZones.java: -------------------------------------------------------------------------------- 1 | package datetime; 2 | 3 | import java.time.LocalDateTime; 4 | import java.time.ZoneId; 5 | import java.time.ZonedDateTime; 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | 9 | import static java.util.Comparator.comparingInt; 10 | 11 | public class AntarcticaTimeZones { 12 | public static void main(String[] args) { 13 | LocalDateTime now = LocalDateTime.now(); 14 | List antarcticZones = 15 | ZoneId.getAvailableZoneIds().stream() // Stream 16 | .filter(regionId -> regionId.contains("Antarctica")) 17 | .map(ZoneId::of) // Stream 18 | .map(now::atZone) // Stream 19 | .sorted(comparingInt( 20 | zoneId -> zoneId.getOffset().getTotalSeconds())) 21 | .collect(Collectors.toList()); 22 | 23 | antarcticZones.forEach(zdt -> 24 | System.out.printf("%7s: %25s %7s%n", zdt.getOffset(), zdt.getZone(), 25 | zdt.getZone().getRules().isDaylightSavings(zdt.toInstant()))); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/http/JokeResponse.java: -------------------------------------------------------------------------------- 1 | package http; 2 | 3 | public class JokeResponse { 4 | private String type; 5 | private Value value; 6 | 7 | public String getType() { 8 | return type; 9 | } 10 | 11 | public void setType(String type) { 12 | this.type = type; 13 | } 14 | 15 | public Value getValue() { 16 | return value; 17 | } 18 | 19 | public void setValue(Value value) { 20 | this.value = value; 21 | } 22 | 23 | public class Value { 24 | private int id; 25 | private String joke; 26 | private String[] categories; 27 | 28 | public int getId() { 29 | return id; 30 | } 31 | 32 | public void setId(int id) { 33 | this.id = id; 34 | } 35 | 36 | public String getJoke() { 37 | return joke; 38 | } 39 | 40 | public void setJoke(String joke) { 41 | this.joke = joke; 42 | } 43 | 44 | public String[] getCategories() { 45 | return categories; 46 | } 47 | 48 | public void setCategories(String[] categories) { 49 | this.categories = categories; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /topics.md: -------------------------------------------------------------------------------- 1 | ## Topics: 2 | 3 | * Lambda expressions 4 | * Method references 5 | * Streams 6 | * Optional 7 | * Lazy streams 8 | * Deferred execution 9 | * The `peek` method 10 | * `map` vs `flatMap` 11 | * Closure composition 12 | * The `reduce` method 13 | * File I/O 14 | * Partitioning and grouping 15 | * Downstream collectors 16 | * Parallel streams 17 | * Exception handling 18 | * The `java.time` package 19 | 20 | ## Parallel streams 21 | 22 | For parallelization to be beneficial: 23 | 24 | * Either a _lot_ of data, or a process that takes a lot of time per element 25 | * Data that is easy to partition 26 | * Stateless and associative operations 27 | 28 | _Don't do anything stateful in parallel_ 29 | 30 | Books: 31 | 32 | * _Modern Java Recipes_, me, O'Reilly Media, 33 | https://www.amazon.com/Modern-Java-Recipes-Solutions-Difficult/dp/149197317X 34 | 35 | * _Modern Java in Action_, Urma, Fusco, and Mycroft, Manning, https://www.manning.com/books/modern-java-in-action 36 | 37 | * _Java SE 8 for the Really Impatient_, Horstmann, Addison-Wesley, https://horstmann.com/java8/ 38 | 39 | * _Functional Programming in Java_, Subramaniam, Pragmatic Bookshelf, https://www.safaribooksonline.com/library/view/functional-programming-in/9781941222690/ -------------------------------------------------------------------------------- /src/main/java/lambdas/FilenameFilterDemo.java: -------------------------------------------------------------------------------- 1 | package lambdas; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | import java.util.Arrays; 6 | import java.util.function.Consumer; 7 | 8 | public class FilenameFilterDemo { 9 | @SuppressWarnings("ConstantConditions") 10 | public static void main(String[] args) { 11 | File directory = new File("src/main/java"); 12 | 13 | // Print all files in directory 14 | String[] fileNames = directory.list(); 15 | System.out.println(Arrays.asList(fileNames)); 16 | 17 | // Print only Java source files in directory 18 | fileNames = directory.list(new FilenameFilter() { 19 | @Override 20 | public boolean accept(File dir, String name) { 21 | return name.endsWith(".java"); 22 | } 23 | }); 24 | System.out.println(Arrays.asList(fileNames)); 25 | 26 | fileNames = directory.list((dir, name) -> name.endsWith(".java")); 27 | System.out.println(Arrays.asList(fileNames)); 28 | 29 | Arrays.stream(fileNames) 30 | .forEach(s -> System.out.println("The current strings is " + s)); 31 | 32 | Arrays.stream(fileNames) 33 | .forEach(System.out::println); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/http/JokeClientTest.java: -------------------------------------------------------------------------------- 1 | package http; 2 | 3 | import org.junit.jupiter.api.Disabled; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.io.IOException; 7 | import java.util.concurrent.ExecutionException; 8 | import java.util.logging.Logger; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertTrue; 11 | 12 | @Disabled("Service no longer available") 13 | class JokeClientTest { 14 | private final Logger logger = Logger.getLogger(JokeClientTest.class.getName()); 15 | 16 | private final JokeClient client = new JokeClient(); 17 | private final String heroFirstName = "Dilip"; 18 | private final String heroLastName = "Thomas"; 19 | 20 | @Test 21 | void getJokeSync() throws IOException, InterruptedException { 22 | String joke = client.getJokeSync(heroFirstName, heroLastName); 23 | logger.info(joke); 24 | assertTrue(joke.contains(heroFirstName) || 25 | joke.contains(heroLastName)); 26 | } 27 | 28 | @Test 29 | void getJokeAsync() throws ExecutionException, InterruptedException { 30 | String joke = client.getJokeAsync(heroFirstName, heroLastName); 31 | logger.info(joke); 32 | assertTrue(joke.contains(heroFirstName) || 33 | joke.contains(heroLastName)); 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/lazy/LazyStreams.java: -------------------------------------------------------------------------------- 1 | package lazy; 2 | 3 | import java.util.Optional; 4 | import java.util.logging.Logger; 5 | import java.util.stream.IntStream; 6 | 7 | public class LazyStreams { 8 | private static final Logger logger = Logger.getLogger(LazyStreams.class.getName()); 9 | 10 | public static int multByTwo(int n) { 11 | System.out.printf("Inside multByTwo with arg %d%n", n); 12 | return n * 2; 13 | } 14 | 15 | public static boolean modByThree(int n) { 16 | System.out.printf("Inside modByThree with arg %d%n", n); 17 | return n % 3 == 0; 18 | } 19 | 20 | public static void main(String[] args) { 21 | // multiply numbers between 100 and 200 by 2, then find first n divisible by 3 22 | int firstEvenDoubleDivBy3 = IntStream.range(100, 200) 23 | .filter(n -> n % 3 == 0) 24 | .map(n -> n * 2) 25 | .findFirst().orElse(0); 26 | System.out.println(firstEvenDoubleDivBy3); 27 | 28 | 29 | // Demonstrate laziness using print statements 30 | firstEvenDoubleDivBy3 = IntStream.range(100, 2_000_000) 31 | .filter(LazyStreams::modByThree) 32 | .map(LazyStreams::multByTwo) 33 | .findFirst().orElse(0); 34 | System.out.printf("First even divisible by 3 is %d%n", firstEvenDoubleDivBy3); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/OptionalDemo.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.List; 3 | import java.util.Optional; 4 | import java.util.stream.IntStream; 5 | import java.util.stream.Stream; 6 | 7 | public class OptionalDemo { 8 | public static void main(String[] args) { 9 | Optional first = Stream.of(3, 1, 4, 1, 5, 9) 10 | .filter(n -> n > 10) 11 | .findFirst(); 12 | 13 | System.out.println(first); 14 | 15 | // System.out.println(first.isPresent() ? (int) first.get() : 0); 16 | 17 | int defaultValue = 0; 18 | System.out.println(first.orElse(defaultValue)); 19 | System.out.println(first.orElseGet(() -> defaultValue)); 20 | first.ifPresent(System.out::println); 21 | 22 | 23 | List strings = Arrays.asList("this", "is", "a", "list", "of", "strings"); 24 | Optional s = strings.stream() 25 | .findFirst(); 26 | 27 | System.out.println(s.orElse("No string found; legal values are: " + strings)); 28 | System.out.println(s.orElseGet(() -> "No string found; legal values are: " + strings)); 29 | System.out.println(s.orElseThrow(IllegalArgumentException::new)); // default constructor 30 | System.out.println(s.orElseThrow(() -> new IllegalArgumentException("Not available"))); 31 | s.ifPresent(System.out::println); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Functional Modern Java 2 | 3 | Source code and examples from the "Functional Modern Java" presentation, showcasing modern Java features and functional programming patterns. 4 | 5 | ## Requirements 6 | 7 | - **Java 21** (LTS) or higher 8 | - **Gradle 8.14.2** or higher (wrapper included) 9 | 10 | ## Building and Running 11 | 12 | ### Build the project 13 | ```bash 14 | ./gradlew build 15 | ``` 16 | 17 | ### Run tests 18 | ```bash 19 | ./gradlew test 20 | ``` 21 | 22 | ### Clean build 23 | ```bash 24 | ./gradlew clean build 25 | ``` 26 | 27 | ## Project Structure 28 | 29 | ``` 30 | src/ 31 | ├── main/java/ # Main source code with Java examples 32 | ├── test/java/ # JUnit 5 test suite 33 | ``` 34 | 35 | ## Technology Stack 36 | 37 | - **Language**: Java 21 (using Gradle toolchain) 38 | - **Build Tool**: Gradle 8.14.2 39 | - **Testing**: JUnit 5.13.2 40 | - **CI**: GitHub Actions 41 | 42 | ## Topics Covered 43 | 44 | This project demonstrates modern Java features including: 45 | - Lambda expressions and functional interfaces 46 | - Stream API and operations 47 | - Optional handling 48 | - Modern collection utilities 49 | - HTTP client examples 50 | - Local variable type inference (var) 51 | - Interface enhancements 52 | - Generics and type safety 53 | 54 | ## Contributing 55 | 56 | All tests use JUnit 5. When adding new tests, follow the existing patterns and ensure compatibility with Java 21. 57 | -------------------------------------------------------------------------------- /src/main/resources/dict/README: -------------------------------------------------------------------------------- 1 | Added to this project from my local macOS machine, 21 Jan 2020 2 | -- Ken Kousen 3 | 4 | # @(#)README 8.1 (Berkeley) 6/5/93 5 | # $FreeBSD$ 6 | 7 | WEB ---- (introduction provided by jaw@riacs) ------------------------- 8 | 9 | Welcome to web2 (Webster's Second International) all 234,936 words worth. 10 | The 1934 copyright has lapsed, according to the supplier. The 11 | supplemental 'web2a' list contains hyphenated terms as well as assorted 12 | noun and adverbial phrases. The wordlist makes a dandy 'grep' victim. 13 | 14 | -- James A. Woods {ihnp4,hplabs}!ames!jaw (or jaw@riacs) 15 | 16 | Country names are stored in the file /usr/share/misc/iso3166. 17 | 18 | 19 | FreeBSD Maintenance Notes --------------------------------------------- 20 | 21 | Note that FreeBSD is not maintaining a historical document, we're 22 | maintaining a list of current [American] English spellings. 23 | 24 | A few words have been removed because their spellings have depreciated. 25 | This list of words includes: 26 | corelation (and its derivatives) "correlation" is the preferred spelling 27 | freen typographical error in original file 28 | freend archaic spelling no longer in use; 29 | masks common typo in modern text 30 | 31 | -- 32 | 33 | A list of technical terms has been added in the file 'freebsd'. This 34 | word list contains FreeBSD/Unix lexicon that is used by the system 35 | documentation. It makes a great ispell(1) personal dictionary to 36 | supplement the standard English language dictionary. 37 | -------------------------------------------------------------------------------- /src/main/resources/dict/connectives: -------------------------------------------------------------------------------- 1 | the 2 | of 3 | and 4 | to 5 | a 6 | in 7 | that 8 | is 9 | was 10 | he 11 | for 12 | it 13 | with 14 | as 15 | his 16 | on 17 | be 18 | at 19 | by 20 | i 21 | this 22 | had 23 | not 24 | are 25 | but 26 | from 27 | or 28 | have 29 | an 30 | they 31 | which 32 | one 33 | you 34 | were 35 | her 36 | all 37 | she 38 | there 39 | would 40 | their 41 | we 42 | him 43 | been 44 | has 45 | when 46 | who 47 | will 48 | more 49 | no 50 | if 51 | out 52 | so 53 | said 54 | what 55 | up 56 | its 57 | about 58 | into 59 | than 60 | them 61 | can 62 | only 63 | other 64 | new 65 | some 66 | could 67 | time 68 | these 69 | two 70 | may 71 | then 72 | do 73 | first 74 | any 75 | my 76 | now 77 | such 78 | like 79 | our 80 | over 81 | man 82 | me 83 | even 84 | most 85 | made 86 | after 87 | also 88 | did 89 | many 90 | before 91 | must 92 | through 93 | back 94 | years 95 | where 96 | much 97 | your 98 | way 99 | well 100 | down 101 | should 102 | because 103 | each 104 | just 105 | those 106 | people 107 | mr 108 | how 109 | too 110 | little 111 | state 112 | good 113 | very 114 | make 115 | world 116 | still 117 | own 118 | see 119 | men 120 | work 121 | long 122 | get 123 | here 124 | between 125 | both 126 | life 127 | being 128 | under 129 | never 130 | day 131 | same 132 | another 133 | know 134 | while 135 | last 136 | might 137 | us 138 | great 139 | old 140 | year 141 | off 142 | come 143 | since 144 | against 145 | go 146 | came 147 | right 148 | used 149 | take 150 | three 151 | -------------------------------------------------------------------------------- /src/test/java/generics/SafeVaragsDemoTest.java: -------------------------------------------------------------------------------- 1 | package generics; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.time.LocalDate; 6 | import java.util.Arrays; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 9 | import static org.junit.jupiter.api.Assertions.assertThrows; 10 | 11 | class SafeVaragsDemoTest { 12 | private final SafeVaragsDemo demo = new SafeVaragsDemo(); 13 | private final LocalDate now = LocalDate.now(); 14 | 15 | @Test 16 | void replaceFirstStringWithDate() { 17 | String[] strings = "s1 s2 s3".split("\\s"); 18 | demo.replaceFirstStringWithDate(now, strings); 19 | 20 | assertArrayEquals(strings, 21 | new String[]{now.toString(), "s2", "s3"}); 22 | } 23 | 24 | @Test 25 | void replaceFirstValueInArray() { 26 | String[] strings = "s1 s2 s3".split("\\s"); 27 | 28 | assertThrows(ArrayStoreException.class, 29 | () -> demo.replaceFirstValueInArray(now, strings)); 30 | } 31 | 32 | @Test 33 | void replaceFirstValueInArrayUsingVarargs() { 34 | assertThrows(ClassCastException.class, 35 | () -> { 36 | Comparable>[] comparables = 37 | demo.replaceFirstValueInArray(now, "s1", "s2", "s3"); 38 | System.out.println(Arrays.toString(comparables)); 39 | }); 40 | } 41 | 42 | @Test 43 | void tickingTimeBomb() { 44 | // No exception thrown until you access any element 45 | demo.replaceFirstValueInArray(now, "s1", "s2", "s2"); 46 | } 47 | } -------------------------------------------------------------------------------- /src/main/java/streams/SumBigDecimals.java: -------------------------------------------------------------------------------- 1 | package streams; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.stream.Stream; 5 | 6 | public class SumBigDecimals { 7 | 8 | public BigDecimal sumFirstN_asDoubles(int n) { 9 | double total = Stream.iterate(BigDecimal.ONE, bd -> bd.add(BigDecimal.ONE)) 10 | .limit(n) 11 | .mapToDouble(BigDecimal::doubleValue) 12 | .sum(); 13 | return new BigDecimal(total + ""); 14 | } 15 | 16 | public BigDecimal sumFirstN_usingReduce(int n) { 17 | return Stream.iterate(BigDecimal.ONE, bd -> bd.add(BigDecimal.ONE)) 18 | .limit(n) 19 | .reduce(BigDecimal::add).orElse(BigDecimal.ZERO); 20 | } 21 | 22 | // Off by one error, because 1 is never doubled 23 | public BigDecimal sumDoubles(int n) { 24 | BigDecimal two = new BigDecimal("2"); 25 | return Stream.iterate(BigDecimal.ONE, bd -> bd.add(BigDecimal.ONE)) 26 | .limit(n) 27 | .reduce((total, e) -> { 28 | System.out.println("total = " + total + ", e = " + e); 29 | return total.add(e.multiply(two)); 30 | }).orElse(BigDecimal.ZERO); 31 | } 32 | 33 | public BigDecimal sumDoublesInitialized(int n) { 34 | BigDecimal two = new BigDecimal("2"); 35 | return Stream.iterate(BigDecimal.ONE, bd -> bd.add(BigDecimal.ONE)) 36 | .limit(n) 37 | .reduce(BigDecimal.ZERO, (total, e) -> { 38 | System.out.println("total = " + total + ", e = " + e); 39 | return total.add(e.multiply(two)); 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/optional/Product.java: -------------------------------------------------------------------------------- 1 | package optional; 2 | 3 | import java.util.Objects; 4 | 5 | public class Product { 6 | private Integer id; 7 | private String name; 8 | private double price; 9 | 10 | public Product(Integer id, String name, double price) { 11 | System.out.println("Inside Product constructor with id=" + id); 12 | this.id = id; 13 | this.name = name; 14 | this.price = price; 15 | } 16 | 17 | public Integer getId() { 18 | return id; 19 | } 20 | 21 | public void setId(Integer id) { 22 | this.id = id; 23 | } 24 | 25 | public String getName() { 26 | return name; 27 | } 28 | 29 | public void setName(String name) { 30 | this.name = name; 31 | } 32 | 33 | public double getPrice() { 34 | return price; 35 | } 36 | 37 | public void setPrice(double price) { 38 | this.price = price; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "Product{" + 44 | "id=" + id + 45 | ", name='" + name + '\'' + 46 | ", price=" + price + 47 | '}'; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) return true; 53 | if (o == null || getClass() != o.getClass()) return false; 54 | Product product = (Product) o; 55 | return Double.compare(product.price, price) == 0 && 56 | Objects.equals(id, product.id) && 57 | Objects.equals(name, product.name); 58 | } 59 | 60 | @Override 61 | public int hashCode() { 62 | return Objects.hash(id, name, price); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/streams/StringExercises.java: -------------------------------------------------------------------------------- 1 | package streams; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | import java.util.Comparator; 8 | import java.util.List; 9 | 10 | public class StringExercises { 11 | private final List strings = Arrays.asList("this", "is", "a", 12 | "list", "of", "strings"); 13 | 14 | @Test 15 | public void stringLengthSort_InnerClass() { // Java 5, 6, 7 16 | Collections.sort(strings, new Comparator() { 17 | @Override 18 | public int compare(String s1, String s2) { 19 | return s1.length() - s2.length(); 20 | } 21 | }); 22 | System.out.println(strings); 23 | } 24 | 25 | @Test 26 | public void stringLengthSort_lambda() { 27 | // Use lambda for the Comparator (reverse sort) 28 | 29 | // Use the "sorted" method on Stream 30 | } 31 | 32 | private static int compareStrings(String s1, String s2) { 33 | return s1.length() - s2.length(); 34 | } 35 | 36 | @Test // Use a lambda that calls 'compareStrings' directly 37 | public void stringLengthSort_methodCall() { 38 | } 39 | 40 | @Test // Use a method ref to 'compareStrings' 41 | public void stringLengthSort_methodRef() { 42 | } 43 | 44 | @Test // Use Comparator.comparingInt 45 | public void stringLengthSort_comparingInt() { 46 | } 47 | 48 | @Test 49 | public void demoCollectors() { 50 | // Get only strings of even length 51 | // Add them to a LinkedList 52 | 53 | // Add the strings to a map of string to length 54 | 55 | // Filter out nulls, then print even-length strings 56 | 57 | // Combine the two predicates and use the result to print non-null, even-length strings 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/CollectorsDemo.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | import java.util.Map; 3 | import java.util.Set; 4 | import java.util.concurrent.ConcurrentSkipListSet; 5 | import java.util.function.Function; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.Stream; 8 | 9 | public class CollectorsDemo { 10 | public static void main(String[] args) { 11 | List nums = Stream.of("this", "is", "a", "collection", "of", "strings") 12 | .parallel() 13 | .map(String::length) 14 | // .map(n -> { 15 | // System.out.println(n); 16 | // return n; 17 | // }) 18 | // equivalent to: 19 | .peek(n -> { 20 | System.out.println("On " + Thread.currentThread().getName() 21 | + ", the value of n before the filter is " + n); 22 | }) 23 | .filter(n -> n % 2 == 0) 24 | .peek(n -> System.out.println("On " + Thread.currentThread().getName() 25 | + ", the value of n after the filter is " + n)) 26 | .collect(Collectors.toList()); 27 | System.out.println(nums); 28 | 29 | Set set = Stream.of("this is a is a collection of strings".split(" ")) 30 | .collect(Collectors.toSet()); 31 | System.out.println(set); 32 | System.out.println(set.getClass().getName()); 33 | 34 | Set collection = 35 | Stream.of("this is a is a collection of strings".split(" ")) 36 | .collect(Collectors.toCollection(ConcurrentSkipListSet::new)); 37 | 38 | Map stringMap = 39 | Stream.of("this is a collection of strings".split(" ")) 40 | .collect(Collectors.toMap(Function.identity(), String::length)); 41 | System.out.println(stringMap); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/http/JokeClient.java: -------------------------------------------------------------------------------- 1 | package http; 2 | 3 | import com.google.gson.Gson; 4 | 5 | import java.io.IOException; 6 | import java.net.URI; 7 | import java.net.http.HttpClient; 8 | import java.net.http.HttpRequest; 9 | import java.net.http.HttpResponse; 10 | import java.time.Duration; 11 | import java.util.concurrent.ExecutionException; 12 | 13 | public class JokeClient { 14 | private final HttpClient client = HttpClient.newBuilder() 15 | .version(HttpClient.Version.HTTP_2) 16 | .connectTimeout(Duration.ofSeconds(2)) 17 | .build(); 18 | private final Gson gson = new Gson(); 19 | 20 | private HttpRequest buildRequest(String first, String last) { 21 | String jokeUrl = "http://api.icndb.com/jokes/random?limitTo=[nerdy]"; 22 | String url = String.format("%s&firstName=%s&lastName=%s", jokeUrl, first, last); 23 | return HttpRequest.newBuilder() 24 | .uri(URI.create(url)) 25 | .GET() 26 | .build(); 27 | } 28 | 29 | public String getJokeSync(String first, String last) throws IOException, InterruptedException { 30 | HttpResponse response = client.send( 31 | buildRequest(first, last), 32 | HttpResponse.BodyHandlers.ofString()); 33 | return getJoke(response.body()); 34 | } 35 | 36 | 37 | public String getJokeAsync(String first, String last) throws ExecutionException, InterruptedException { 38 | String json = client.sendAsync(buildRequest(first, last), 39 | HttpResponse.BodyHandlers.ofString()) 40 | .thenApply(HttpResponse::body) 41 | .get(); 42 | return getJoke(json); 43 | } 44 | 45 | private String getJoke(String jsonData) { 46 | return gson.fromJson(jsonData, JokeResponse.class) 47 | .getValue().getJoke(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/sorting/Golfer.java: -------------------------------------------------------------------------------- 1 | package sorting; 2 | 3 | public class Golfer implements Comparable { 4 | private String first; 5 | private String last; 6 | private int score; 7 | 8 | public Golfer() {} 9 | 10 | public Golfer(String first, String last) { 11 | this.first = first; 12 | this.last = last; 13 | } 14 | 15 | public Golfer(String first, String last, int score) { 16 | this.first = first; 17 | this.last = last; 18 | this.score = score; 19 | } 20 | 21 | @Override 22 | public int compareTo(Golfer golfer) { 23 | return score - golfer.score; 24 | } 25 | 26 | public String getFirst() { 27 | return first; 28 | } 29 | 30 | public void setFirst(String first) { 31 | this.first = first; 32 | } 33 | 34 | public String getLast() { 35 | return last; 36 | } 37 | 38 | public void setLast(String last) { 39 | this.last = last; 40 | } 41 | 42 | public int getScore() { 43 | return score; 44 | } 45 | 46 | public void setScore(int score) { 47 | this.score = score; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) return true; 53 | if (o == null || getClass() != o.getClass()) return false; 54 | 55 | Golfer golfer = (Golfer) o; 56 | 57 | if (first != null ? !first.equals(golfer.first) : golfer.first != null) return false; 58 | return last != null ? last.equals(golfer.last) : golfer.last == null; 59 | 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | int result = first != null ? first.hashCode() : 0; 65 | result = 31 * result + (last != null ? last.hashCode() : 0); 66 | return result; 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return "Golfer{" + 72 | "first='" + first + '\'' + 73 | ", last='" + last + '\'' + 74 | ", score=" + score + 75 | '}'; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/sorting/SortGolfers.java: -------------------------------------------------------------------------------- 1 | package sorting; 2 | 3 | import java.util.Arrays; 4 | import java.util.Comparator; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.stream.Collectors; 8 | 9 | public class SortGolfers { 10 | private final List golfers = Arrays.asList( 11 | new Golfer("Jack", "Nicklaus", 68), 12 | new Golfer("Tiger", "Woods", 70), 13 | new Golfer("Tom", "Watson", 70), 14 | new Golfer("Ty", "Webb", 68), 15 | new Golfer("Bubba", "Watson", 70) 16 | ); 17 | 18 | // default sort is by score 19 | public void defaultSort() { 20 | golfers.stream() 21 | .sorted() 22 | .forEach(System.out::println); 23 | } 24 | 25 | // sort by score, then equal scores by last name 26 | public void sortByScoreThenLast() { 27 | golfers.stream() 28 | .sorted(Comparator.comparingInt(Golfer::getScore) 29 | .thenComparing(Golfer::getLast)) 30 | .forEach(System.out::println); 31 | } 32 | 33 | // sort by score, then by last, then by first 34 | public void sortByScoreThenLastThenFirst() { 35 | golfers.stream() 36 | .sorted(Comparator.comparingInt(Golfer::getScore) 37 | .thenComparing(Golfer::getLast) 38 | .thenComparing(Golfer::getFirst)) 39 | .forEach(System.out::println); 40 | } 41 | 42 | public void partitionByScore() { 43 | Map> map = golfers.stream() 44 | .collect(Collectors.partitioningBy( 45 | golfer -> golfer.getScore() < 70)); 46 | 47 | map.forEach((k,v) -> { 48 | System.out.println(k); 49 | v.forEach(System.out::println); 50 | }); 51 | } 52 | 53 | public static void main(String[] args) { 54 | SortGolfers sg = new SortGolfers(); 55 | // sg.defaultSort(); 56 | // sg.sortByScoreThenLast(); 57 | sg.sortByScoreThenLastThenFirst(); 58 | // sg.partitionByScore(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/streams/FlatMapDemo.java: -------------------------------------------------------------------------------- 1 | package streams; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.stream.Stream; 6 | 7 | public class FlatMapDemo { 8 | public static void main(String[] args) { 9 | 10 | Customer sheridan = new Customer("Sheridan"); 11 | Customer ivanova = new Customer("Ivanova"); 12 | Customer garibaldi = new Customer("Garibaldi"); 13 | 14 | sheridan.addOrder(new Order(1)) 15 | .addOrder(new Order(2)) 16 | .addOrder(new Order(3)); 17 | ivanova.addOrder(new Order(4)) 18 | .addOrder(new Order(5)); 19 | 20 | List customers = Arrays.asList(sheridan, ivanova, garibaldi); 21 | 22 | // map for 1-1 customer to name --> Stream 23 | customers.stream() 24 | .map(Customer::getName) // function 25 | .forEach(System.out::println); 26 | 27 | // map 1-many customer to orders --> Stream> 28 | customers.stream() 29 | .map(Customer::getOrders) // function> 30 | .forEach(System.out::println); 31 | 32 | // map 1-many customer to orders.stream() --> Stream> 33 | customers.stream() 34 | .map(customer -> customer.getOrders().stream()) // function> 35 | .forEach(System.out::println); 36 | 37 | // stream() on an empty collection is already an empty Stream 38 | customers.stream() 39 | .flatMap(customer -> customer.getOrders().stream()) // function> 40 | .forEach(System.out::println); 41 | 42 | // flatMap 1-many customer to orders.stream() --> Stream 43 | // Note: extra detail included just for illustration; 44 | // stream() on an empty collection already returns an empty stream 45 | customers.stream() 46 | .flatMap(customer -> 47 | customer.getOrders().size() == 0 ? Stream.empty() : 48 | customer.getOrders().stream()) 49 | .forEach(System.out::println); 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/collections/ImmutableCollectionsTest.java: -------------------------------------------------------------------------------- 1 | package collections; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.List; 6 | import java.util.stream.IntStream; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | import static org.junit.jupiter.api.Assertions.assertThrows; 10 | 11 | public class ImmutableCollectionsTest { 12 | 13 | private Integer[] intArgs(int n) { 14 | return IntStream.rangeClosed(1, n) 15 | .boxed() 16 | .toArray(Integer[]::new); 17 | } 18 | 19 | @Test 20 | public void createImmutableList() { 21 | IntStream.rangeClosed(1, 10) 22 | .forEach(n -> { 23 | List intList = List.of(intArgs(n)); 24 | assertEquals(n, intList.size()); 25 | assertEquals(1, intList.get(0).intValue()); 26 | assertEquals(n, intList.get(intList.size() - 1).intValue()); 27 | }); 28 | } 29 | 30 | @Test 31 | public void showImmutabilityAdd() { 32 | List intList = List.of(1, 2, 3); 33 | assertThrows(UnsupportedOperationException.class, () -> intList.add(99)); 34 | } 35 | 36 | @Test 37 | public void showImmutabilityClear() { 38 | List intList = List.of(1, 2, 3); 39 | assertThrows(UnsupportedOperationException.class, intList::clear); 40 | } 41 | 42 | @Test 43 | public void showImmutabilityRemove() { 44 | List intList = List.of(1, 2, 3); 45 | assertThrows(UnsupportedOperationException.class, () -> intList.remove(0)); 46 | } 47 | 48 | @Test 49 | public void showImmutabilityReplace() { 50 | List intList = List.of(1, 2, 3); 51 | assertThrows(UnsupportedOperationException.class, () -> intList.replaceAll(n -> -n)); 52 | } 53 | 54 | @Test 55 | public void showImmutabilitySet() { 56 | List intList = List.of(1, 2, 3); 57 | assertThrows(UnsupportedOperationException.class, () -> intList.set(0, 99)); 58 | } 59 | 60 | @Test 61 | public void testVarargsList() { 62 | List intList = List.of(intArgs(11)); 63 | assertEquals(11, intList.size()); 64 | assertEquals( 1, intList.get(0).intValue()); 65 | assertEquals(11, intList.get(intList.size() - 1).intValue()); 66 | } 67 | } -------------------------------------------------------------------------------- /src/main/java/sorting/SortStrings.java: -------------------------------------------------------------------------------- 1 | package sorting; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.Comparator; 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | 9 | public class SortStrings { 10 | public static void main(String[] args) { 11 | List strings = Arrays.asList("this", "is", "a", "list", "of", "strings"); 12 | 13 | System.out.println(strings); 14 | 15 | System.out.println("Natural sort:"); 16 | Collections.sort(strings); 17 | System.out.println(strings); 18 | 19 | System.out.println("Sort by length using a Comparator impl anon inner class:"); 20 | Collections.sort(strings, new Comparator() { 21 | @Override 22 | public int compare(String s1, String s2) { 23 | return s1.length() - s2.length(); 24 | } 25 | }); 26 | System.out.println(strings); 27 | 28 | System.out.println("Reverse sort by length with a Comparator impl lambda expression:"); 29 | Collections.sort(strings, (s1, s2) -> s2.length() - s1.length()); 30 | System.out.println(strings); 31 | 32 | // Stream has a sorted() method that is not destructive 33 | System.out.println("Natural sort using Stream.sorted()"); 34 | List sorted = strings.stream() 35 | .sorted() 36 | .collect(Collectors.toList()); 37 | System.out.println(sorted); 38 | 39 | System.out.println("Reverse length sort using Stream.sorted(Comparator)"); 40 | sorted = strings.stream() 41 | .sorted((s1, s2) -> s2.length() - s1.length()) 42 | .collect(Collectors.toList()); 43 | System.out.println(sorted); 44 | 45 | System.out.println("Sort by length using Comparator.comparingInt()"); 46 | sorted = strings.stream() 47 | .sorted(Comparator.comparingInt(String::length)) 48 | .collect(Collectors.toList()); 49 | System.out.println(sorted); 50 | 51 | System.out.println("Sort by length, then equal lengths reverse alpha"); 52 | sorted = strings.stream() 53 | .sorted(Comparator.comparingInt(String::length) 54 | .thenComparing(Comparator.reverseOrder())) 55 | .collect(Collectors.toList()); 56 | System.out.println(sorted); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/lambdas/FunctionalInterfacesTest.java: -------------------------------------------------------------------------------- 1 | package lambdas; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | import java.util.function.Consumer; 8 | 9 | public class FunctionalInterfacesTest { 10 | 11 | @SuppressWarnings({"Convert2Lambda", "Anonymous2MethodRef"}) 12 | @Test 13 | public void implementConsumerUsingAnonInnerClass() throws Exception { 14 | Consumer consumer = new Consumer() { 15 | @Override 16 | public void accept(String s) { 17 | System.out.println(s); 18 | } 19 | }; 20 | consumer.accept("Hello, World!"); 21 | } 22 | 23 | @Test 24 | public void implementConsumerUsingLambda() throws Exception { 25 | // consumer.accept("Hello, World!"); 26 | } 27 | 28 | @Test 29 | public void implementConsumerUsingMethodReference() throws Exception { 30 | // consumer.accept("Hello, World!"); 31 | } 32 | 33 | @Test 34 | public void implementSupplierUsingAnonInnerClass() throws Exception { 35 | // assertEquals("Hello", supplier.get()); 36 | } 37 | 38 | @Test 39 | public void implementSupplierUsingLambda() throws Exception { 40 | // assertEquals("Hello", supplier.get()); 41 | } 42 | 43 | @Test 44 | public void implementSupplierUsingMethodReference() throws Exception { 45 | // Create a Supplier that calls Math.random() 46 | // assertTrue(supplier.get() >= 0.0); 47 | // assertTrue(supplier.get() <= 1.0); 48 | 49 | // Create a DoubleSupplier that does the same 50 | // assertTrue(doubleSupplier.getAsDouble() >= 0.0); 51 | // assertTrue(doubleSupplier.getAsDouble() <= 1.0); 52 | } 53 | 54 | @Test 55 | public void constructorReference() throws Exception { 56 | List stringList = Arrays.asList("a", "b", "b", "c", "d", "d"); 57 | // assertEquals(6, stringList.size()); 58 | 59 | // Add the strings to a Set 60 | // assertEquals(4, strings.size()); 61 | // assertEquals(HashSet.class, strings.getClass()); 62 | 63 | // Add the strings to a TreeSet 64 | // assertEquals(4, sortedStrings.size()); 65 | // assertEquals(TreeSet.class, sortedStrings.getClass()); 66 | // assertEquals("a", sortedStrings.first()); 67 | } 68 | 69 | @Test 70 | public void filterWithPredicate() throws Exception { 71 | // IntStream.of(3, 1, 4, 1, 5, 9) 72 | // .filter(n -> true) // accept even nums only 73 | // .forEach(n -> assertTrue(n % 2 == 0)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/lvti/VarTypeTest.java: -------------------------------------------------------------------------------- 1 | package lvti; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | import static org.junit.jupiter.api.Assertions.assertTrue; 11 | 12 | @SuppressWarnings({"UnnecessaryBoxing", "ConstantConditions", "UnnecessaryLocalVariable", "MismatchedQueryAndUpdateOfCollection"}) 13 | public class VarTypeTest { 14 | @Test 15 | void inferString() { 16 | var s = "Hello, World!"; 17 | assertEquals(String.class, s.getClass()); 18 | } 19 | 20 | @Test 21 | void inferInteger() { 22 | var num = 3; 23 | assertTrue(Integer.valueOf(num) instanceof Integer); 24 | } 25 | 26 | @Test 27 | void inferListOfString() { 28 | var strings = List.of("this", "is", "a", "list", "of", "strings"); 29 | System.out.println(strings.getClass().getName()); 30 | assertTrue(strings instanceof List); 31 | 32 | List nums = new ArrayList<>(); 33 | nums.add(3); nums.add(1); nums.add(4); 34 | var numsVar = nums; 35 | System.out.println(numsVar.getClass().getName()); 36 | assertEquals(ArrayList.class, numsVar.getClass()); 37 | } 38 | 39 | @Test 40 | void inferArrayListOfString() { 41 | var strings = new ArrayList(); 42 | assertEquals(ArrayList.class, strings.getClass()); 43 | } 44 | 45 | @Test 46 | void loopOverComplicatedMap() { 47 | Map> map = Map.ofEntries( 48 | Map.entry("a", List.of(1, 2, 3)), 49 | Map.entry("b", List.of(1, 2, 3)), 50 | Map.entry("c", List.of(1, 2, 3)), 51 | Map.entry("d", List.of(1, 2, 3))); 52 | 53 | // LVTI useful in for loops and try-with-resource blocks 54 | for (var e : map.entrySet()) { 55 | System.out.println(e.getKey() + ": " + e.getValue()); 56 | } 57 | } 58 | 59 | @Test 60 | void inferredAnonymousType() { 61 | var v = new Runnable() { 62 | public void run() { 63 | System.out.println("Running..."); 64 | } 65 | 66 | public void runTwice() { 67 | run(); 68 | run(); 69 | } 70 | }; 71 | 72 | v.runTwice(); 73 | } 74 | 75 | @Test 76 | void nullProblem() { 77 | // var x = null; 78 | } 79 | 80 | @Test 81 | void dontDoThis() { 82 | var var = new Var("var"); 83 | } 84 | } 85 | 86 | class Var { 87 | private final String var; 88 | 89 | public Var(String var) { 90 | this.var = var; 91 | } 92 | 93 | public String getVar() { 94 | return var; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/test/java/got/MemberDAOTests.java: -------------------------------------------------------------------------------- 1 | package got; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Collection; 6 | 7 | public class MemberDAOTests { 8 | private final Collection allMembers = InMemoryMemberDAO.getInstance().getAll(); 9 | 10 | /** 11 | * Find all members whose name starts with S and sort by id (natural sort) 12 | */ 13 | @Test 14 | public void startWithS_sortByAlpha() { 15 | } 16 | 17 | /** 18 | * Final all Starks and sort them by name 19 | */ 20 | @Test 21 | public void starks_alphaByName() { 22 | } 23 | 24 | /** 25 | * Find all members whose salary is less than 80K and sort by house 26 | */ 27 | @Test 28 | public void salaryLessThan_sortByHouseName() { 29 | } 30 | 31 | /** 32 | * Sort members by house name, then by name 33 | */ 34 | @Test 35 | public void sortByHouseName_sortByNameDesc() { 36 | } 37 | 38 | /** 39 | * Sort the Starks by birthdate 40 | */ 41 | @Test 42 | public void starksByDob() { 43 | } 44 | 45 | /** 46 | * Find all Kings and sort by name in descending order 47 | */ 48 | @Test 49 | public void kingsByNameDesc() { 50 | } 51 | 52 | /** 53 | * Find the average salary 54 | */ 55 | @Test 56 | public void averageSalary() { 57 | } 58 | 59 | /** 60 | * Get the names of all the Starks, sorted in natural order 61 | * (note _names_, not members) 62 | */ 63 | @Test 64 | public void namesSorted() { 65 | } 66 | 67 | /** 68 | * Are all the salaries greater than 100K? 69 | */ 70 | @Test 71 | public void salariesGT100k() { 72 | } 73 | 74 | /** 75 | * Are there any members of House Greyjoy? 76 | */ 77 | @Test 78 | public void greyjoys() { 79 | } 80 | 81 | /** 82 | * How many Lannisters are there? 83 | */ 84 | @Test 85 | public void howManyLannisters() { 86 | } 87 | 88 | /** 89 | * Print the names of any three Lannisters 90 | */ 91 | @Test 92 | public void threeLannisters() { 93 | } 94 | 95 | /** 96 | * Print the names of the Lannisters as a comma-separated string 97 | */ 98 | @Test 99 | public void lannisterNames() { 100 | } 101 | 102 | /** 103 | * Who has the highest salary? 104 | */ 105 | @Test 106 | public void highestSalary() { 107 | } 108 | 109 | /** 110 | * Partition members into male and female 111 | * (note: women are LADY or QUEEN, men are everything else) 112 | */ 113 | @Test 114 | public void menVsWomen() { 115 | } 116 | 117 | /** 118 | * Group members into Houses 119 | */ 120 | @Test 121 | public void membersByHouse() { 122 | } 123 | 124 | /** 125 | * How many members are in each house? 126 | * (group by house, downstream collector using count 127 | */ 128 | @Test 129 | public void numberOfMembersByHouse() { 130 | } 131 | 132 | /** 133 | * Get the max, min, and ave salary for each house 134 | */ 135 | @Test 136 | public void houseStats() { 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /src/test/java/collections/ImmutableMapTest.java: -------------------------------------------------------------------------------- 1 | package collections; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Collection; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | import static java.util.Map.entry; 11 | import static java.util.Map.ofEntries; 12 | import static org.junit.jupiter.api.Assertions.*; 13 | 14 | @SuppressWarnings("ResultOfMethodCallIgnored") 15 | public class ImmutableMapTest { 16 | 17 | @Test 18 | void setOf() { 19 | Set letters = Set.of("a", "b"); 20 | assertEquals(2, letters.size()); 21 | } 22 | 23 | @Test 24 | void listOf() { 25 | List letters = List.of("a", "b"); 26 | assertEquals(2, letters.size()); 27 | } 28 | 29 | @Test 30 | void addingElementThrowsUOE() { 31 | List strings = List.of("a", "b"); 32 | assertThrows(UnsupportedOperationException.class, 33 | () -> strings.add("c")); 34 | } 35 | 36 | @Test 37 | void setOfDuplicates() { 38 | assertThrows(IllegalArgumentException.class, () -> Set.of("a", "a")); 39 | } 40 | 41 | @Test 42 | void mapWithNulls() { 43 | assertAll("No null keys or values", 44 | () -> assertThrows(NullPointerException.class, () -> Map.of(null, "value")), 45 | () -> assertThrows(NullPointerException.class, () -> Map.of("key", null))); 46 | } 47 | 48 | @Test 49 | void noDuplicateKeysInMap() { 50 | assertThrows(IllegalArgumentException.class, 51 | () -> ofEntries(entry("k1", "v1"), 52 | entry("k2", "v1"), 53 | entry("k1", "v2"))); 54 | } 55 | 56 | @Test 57 | public void immutableMapFromEntries() { 58 | Map jvmLanguages = ofEntries( 59 | entry("Java", "http://www.oracle.com/technetwork/java/index.html"), 60 | entry("Groovy", "http://groovy-lang.org/"), 61 | entry("Scala", "http://www.scala-lang.org/"), 62 | entry("Clojure", "https://clojure.org/"), 63 | entry("Kotlin", "http://kotlinlang.org/")); 64 | 65 | Set names = Set.of("Java", "Scala", "Groovy", "Clojure", "Kotlin"); 66 | 67 | List urls = List.of( 68 | "http://www.oracle.com/technetwork/java/index.html", 69 | "http://groovy-lang.org/", 70 | "http://www.scala-lang.org/", 71 | "https://clojure.org/", 72 | "http://kotlinlang.org/"); 73 | 74 | Set keys = jvmLanguages.keySet(); 75 | Collection values = jvmLanguages.values(); 76 | names.forEach(name -> assertTrue(keys.contains(name))); 77 | urls.forEach(url -> assertTrue(values.contains(url))); 78 | 79 | Map javaMap = Map.of( 80 | "Java", 81 | "http://www.oracle.com/technetwork/java/index.html", 82 | "Groovy", 83 | "http://groovy-lang.org/", 84 | "Scala", 85 | "http://www.scala-lang.org/", 86 | "Clojure", 87 | "https://clojure.org/", 88 | "Kotlin", 89 | "http://kotlinlang.org/"); 90 | javaMap.forEach((name, url) -> assertTrue( 91 | jvmLanguages.containsKey(name) && jvmLanguages.containsValue(url))); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/got/Member.java: -------------------------------------------------------------------------------- 1 | package got; 2 | 3 | import java.time.LocalDate; 4 | 5 | public class Member implements Comparable { 6 | private Long id; 7 | private Title title = Title.LORD; 8 | private String name; 9 | private LocalDate dob; 10 | private double salary; 11 | private House house; 12 | 13 | public Member(Long id, Title title, String name, LocalDate dob, double salary, House house) { 14 | this.id = id; 15 | this.title = title; 16 | this.name = name; 17 | this.dob = dob; 18 | this.salary = salary; 19 | this.house = house; 20 | } 21 | 22 | @Override 23 | public int compareTo(Member member) { 24 | return id.compareTo(member.id); 25 | } 26 | 27 | public Long getId() { 28 | return id; 29 | } 30 | 31 | public void setId(Long id) { 32 | this.id = id; 33 | } 34 | 35 | public Title getTitle() { 36 | return title; 37 | } 38 | 39 | public void setTitle(Title title) { 40 | this.title = title; 41 | } 42 | 43 | public String getName() { 44 | return name; 45 | } 46 | 47 | public void setName(String name) { 48 | this.name = name; 49 | } 50 | 51 | public LocalDate getDob() { 52 | return dob; 53 | } 54 | 55 | public void setDob(LocalDate dob) { 56 | this.dob = dob; 57 | } 58 | 59 | public double getSalary() { 60 | return salary; 61 | } 62 | 63 | public void setSalary(double salary) { 64 | this.salary = salary; 65 | } 66 | 67 | public House getHouse() { 68 | return house; 69 | } 70 | 71 | public String getHouseName() { 72 | return house.getName(); 73 | } 74 | 75 | public void setHouse(House house) { 76 | this.house = house; 77 | } 78 | 79 | @Override 80 | public String toString() { 81 | return "Member{" + 82 | "id=" + id + 83 | ", title=" + title + 84 | ", name='" + name + '\'' + 85 | ", dob=" + dob + 86 | ", salary=" + salary + 87 | ", house=" + house + 88 | '}'; 89 | } 90 | 91 | @Override 92 | public boolean equals(Object o) { 93 | if (this == o) return true; 94 | if (o == null || getClass() != o.getClass()) return false; 95 | 96 | Member member = (Member) o; 97 | 98 | if (Double.compare(member.salary, salary) != 0) return false; 99 | if (!id.equals(member.id)) return false; 100 | if (title != member.title) return false; 101 | if (!name.equals(member.name)) return false; 102 | if (dob != null ? !dob.equals(member.dob) : member.dob != null) return false; 103 | return house != null ? house.equals(member.house) : member.house == null; 104 | 105 | } 106 | 107 | @Override 108 | public int hashCode() { 109 | int result; 110 | long temp; 111 | result = id.hashCode(); 112 | result = 31 * result + title.hashCode(); 113 | result = 31 * result + name.hashCode(); 114 | result = 31 * result + (dob != null ? dob.hashCode() : 0); 115 | temp = Double.doubleToLongBits(salary); 116 | result = 31 * result + (int) (temp ^ (temp >>> 32)); 117 | result = 31 * result + (house != null ? house.hashCode() : 0); 118 | return result; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/got/InMemoryMemberDAO.java: -------------------------------------------------------------------------------- 1 | package got; 2 | 3 | import java.time.LocalDate; 4 | import java.time.Month; 5 | import java.util.*; 6 | import java.util.stream.Collectors; 7 | 8 | public class InMemoryMemberDAO implements MemberDAO { 9 | private static final MemberDAO dao = new InMemoryMemberDAO(); 10 | 11 | private final List allMembers = Arrays.asList( 12 | new Member(1L, Title.LORD, "Eddard", LocalDate.of(1959, Month.APRIL, 17), 100000.0, new House("Stark")), 13 | new Member(2L, Title.LADY, "Catelyn", LocalDate.of(1964, Month.JANUARY, 17), 80000.0, new House("Stark")), 14 | new Member(3L, Title.LADY, "Arya", LocalDate.of(1997, Month.APRIL, 15), 50000.0, new House("Stark")), 15 | new Member(4L, Title.LADY, "Sansa", LocalDate.of(1996, Month.FEBRUARY, 21), 60000.0, new House("Stark")), 16 | new Member(5L, Title.SIR, "Bran", LocalDate.of(1999, Month.APRIL, 9), 10000.0, new House("Stark")), 17 | new Member(6L, Title.KING, "Robb", LocalDate.of(1986, Month.JUNE, 18), 100000.0, new House("Stark")), 18 | new Member(7L, Title.KING, "Jon", LocalDate.of(1986, Month.DECEMBER, 26), 90000.0, new House("Snow")), 19 | new Member(8L, Title.SIR, "Jaime", LocalDate.of(1970, Month.JULY, 27), 120000.0, new House("Lannister")), 20 | new Member(9L, Title.LORD, "Tyrion", LocalDate.of(1969, Month.JUNE, 11), 70000.0, new House("Lannister")), 21 | new Member(10L, Title.LORD, "Tywin", LocalDate.of(1946, Month.OCTOBER, 10), 200000.0, new House("Lannister")), 22 | new Member(11L, Title.LADY, "Cersei", LocalDate.of(1973, Month.OCTOBER, 3), 120000.0, new House("Lannister")), 23 | new Member(12L, Title.QUEEN, "Daenerys", LocalDate.of(1987, Month.MAY, 1), 130000.0, new House("Targaryen")), 24 | new Member(13L, Title.LORD, "Viserys", LocalDate.of(1983, Month.NOVEMBER, 17), 100000.0, new House("Targaryen")), 25 | new Member(14L, Title.KING, "Robert", LocalDate.of(1964, Month.JANUARY, 14), 180000.0, new House("Baratheon")), 26 | new Member(15L, Title.KING, "Joffrey", LocalDate.of(1992, Month.MAY, 20), 100000.0, new House("Baratheon")), 27 | new Member(16L, Title.KING, "Tommen", LocalDate.of(1997, Month.SEPTEMBER, 7), 60000.0, new House("Baratheon")), 28 | new Member(17L, Title.KING, "Stannis", LocalDate.of(1957, Month.MARCH, 27), 123456.0, new House("Baratheon")), 29 | new Member(18L, Title.QUEEN, "Margaery", LocalDate.of(1982, Month.FEBRUARY, 11), 80000.0, new House("Tyrell")), 30 | new Member(19L, Title.SIR, "Loras", LocalDate.of(1988, Month.MARCH, 24), 70000.0, new House("Tyrell")), 31 | new Member(20L, Title.LADY, "Olenna", LocalDate.of(1938, Month.JULY, 20), 130000.0, new House("Tyrell")), 32 | new Member(21L, Title.LORD, "Roose", LocalDate.of(1963, Month.SEPTEMBER, 12), 100000.0, new House("Bolton")), 33 | new Member(22L, Title.LORD, "Ramsay", LocalDate.of(1985, Month.MAY, 13), 140000.0, new House("Bolton")) 34 | ); 35 | 36 | private InMemoryMemberDAO() {} 37 | 38 | public static MemberDAO getInstance() { 39 | return dao; 40 | } 41 | 42 | @Override 43 | public Member findById(Long id) { 44 | return allMembers.stream() 45 | .filter(member -> member.getId().equals(id)) 46 | .findFirst().orElse(null); 47 | } 48 | 49 | @Override 50 | public Optional findByName(String name) { 51 | return allMembers.stream() 52 | .filter(member -> member.getName().equals(name)) 53 | .findFirst(); 54 | } 55 | 56 | @Override 57 | public List findAllByHouse(House house) { 58 | return allMembers.stream() 59 | .filter(member -> member.getHouse().equals(house)) 60 | .collect(Collectors.toList()); 61 | } 62 | 63 | @Override 64 | public Collection getAll() { 65 | return Collections.unmodifiableCollection(allMembers); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/io/ProcessDictionary.java: -------------------------------------------------------------------------------- 1 | package io; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileReader; 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | import java.util.Comparator; 10 | import java.util.Map; 11 | import java.util.stream.Collectors; 12 | import java.util.stream.Stream; 13 | 14 | import static java.util.stream.Collectors.counting; 15 | import static java.util.stream.Collectors.groupingBy; 16 | 17 | @SuppressWarnings("DuplicatedCode") 18 | public class ProcessDictionary { 19 | private final Path dictionary = Paths.get("/usr/share/dict/words"); 20 | 21 | public void printTenLongestWords() { 22 | System.out.println("\nTen Longest Words:"); 23 | try (Stream lines = Files.lines(dictionary)) { 24 | lines.filter(s -> s.length() > 20) 25 | .sorted(Comparator.comparingInt(String::length).reversed() 26 | //.thenComparing(Comparator.reverseOrder())) 27 | ) 28 | .limit(10) 29 | .forEach(w -> 30 | System.out.printf("%s (%d)%n", w, w.length())); 31 | } catch (IOException e) { 32 | e.printStackTrace(); 33 | } 34 | } 35 | 36 | public void printWordsOfEachLength() { 37 | System.out.println("\nList of words of each length:"); 38 | try (Stream lines = Files.lines(dictionary)) { 39 | lines.filter(s -> s.length() > 20) 40 | .collect(Collectors.groupingBy(String::length)) // Map> 41 | .forEach((len, wordList) -> System.out.println(len + ": " + wordList)); 42 | } catch (IOException e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | 47 | public void printHowManyWordsOfEachLength() { 48 | System.out.println("\nNumber of words of each length:"); 49 | try (Stream lines = Files.lines(dictionary)) { 50 | lines.filter(s -> s.length() > 20) 51 | .collect(Collectors.groupingBy(String::length, Collectors.counting())) // Map 52 | .forEach((len, num) -> System.out.printf("%d: %d%n", len, num)); 53 | } catch (IOException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | 58 | public void printSortedMapOfWords() { 59 | System.out.println("\nNumber of words of each length (desc order):"); 60 | try (Stream lines = Files.lines(dictionary)) { 61 | Map map = lines.filter(s -> s.length() > 20) 62 | .collect(groupingBy(String::length, counting())); 63 | 64 | map.entrySet().stream() 65 | .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())) 66 | .forEach(e -> System.out.printf("Length %d: %d words%n", e.getKey(), e.getValue())); 67 | } catch (IOException e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | public void printSortedMapOfWordsUsingBufferedReader() { 73 | System.out.println("\nNumber of words of each length (desc order):"); 74 | try (Stream lines = 75 | new BufferedReader(new FileReader("/usr/share/dict/words")).lines()) { 76 | Map map = lines.filter(s -> s.length() > 20) 77 | .collect(groupingBy(String::length, counting())); 78 | 79 | map.entrySet().stream() 80 | .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())) 81 | .forEach(e -> System.out.printf("Length %d: %d words%n", e.getKey(), e.getValue())); 82 | } catch (IOException e) { 83 | e.printStackTrace(); 84 | } 85 | } 86 | 87 | public static void main(String[] args) { 88 | ProcessDictionary processDictionary = new ProcessDictionary(); 89 | processDictionary.printTenLongestWords(); 90 | processDictionary.printWordsOfEachLength(); 91 | processDictionary.printHowManyWordsOfEachLength(); 92 | processDictionary.printSortedMapOfWords(); 93 | processDictionary.printSortedMapOfWordsUsingBufferedReader(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/fileio/ProcessDictionary.java: -------------------------------------------------------------------------------- 1 | package fileio; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileReader; 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | import java.util.Comparator; 10 | import java.util.Map; 11 | import java.util.logging.Logger; 12 | import java.util.stream.Stream; 13 | 14 | import static java.util.stream.Collectors.counting; 15 | import static java.util.stream.Collectors.groupingBy; 16 | 17 | @SuppressWarnings("GrazieInspection") 18 | public class ProcessDictionary { 19 | private final Path dictionary = Paths.get("src/main/resources/dict/words"); 20 | private final Logger logger = Logger.getLogger("default"); 21 | 22 | public void printTenLongestWords() { 23 | System.out.println("\nTen Longest Words:"); 24 | try (Stream lines = Files.lines(dictionary)) { 25 | lines.filter(s -> s.length() > 20) 26 | .sorted(Comparator.comparingInt(String::length).reversed() 27 | //.thenComparing(Comparator.reverseOrder())) 28 | ) 29 | .limit(10) 30 | .forEach(w -> System.out.printf("%s (%d)%n", w, w.length())); 31 | // .forEach(w -> logger.info(() -> "the word is " + w + " and its length is " + w.length())); 32 | } catch (IOException e) { 33 | e.printStackTrace(); 34 | } 35 | } 36 | 37 | public void printWordsOfEachLength() { 38 | System.out.println("\nList of words of each length:"); 39 | try (Stream lines = Files.lines(dictionary)) { 40 | lines.filter(s -> s.length() > 20) 41 | .collect(groupingBy(String::length)) // Map> 42 | .forEach((len, wordList) -> System.out.println(len + ": " + wordList)); 43 | } catch (IOException e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | 48 | public void printHowManyWordsOfEachLength() { 49 | System.out.println("\nNumber of words of each length:"); 50 | try (Stream lines = Files.lines(dictionary)) { 51 | lines.filter(s -> s.length() > 20) 52 | .collect(groupingBy(String::length, counting())) // Map 53 | .forEach((len, num) -> System.out.printf("%d: %d%n", len, num)); 54 | } catch (IOException e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | 59 | public void printSortedMapOfWords() { 60 | System.out.println("\nNumber of words of each length (desc order):"); 61 | try (Stream lines = Files.lines(dictionary)) { 62 | Map map = lines.filter(s -> s.length() > 20) 63 | .collect(groupingBy(String::length, counting())); 64 | 65 | map.entrySet().stream() 66 | .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())) 67 | .forEach(e -> System.out.printf("Length %d: %d words%n", e.getKey(), e.getValue())); 68 | } catch (IOException e) { 69 | e.printStackTrace(); 70 | } 71 | } 72 | 73 | public void printSortedMapOfWordsUsingBufferedReader() { 74 | System.out.println("\nNumber of words of each length (desc order):"); 75 | try (Stream lines = 76 | new BufferedReader(new FileReader("/usr/share/dict/words")).lines()) { 77 | Map map = lines.filter(s -> s.length() > 20) 78 | .collect(groupingBy(String::length, counting())); 79 | 80 | map.entrySet().stream() 81 | .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())) 82 | .forEach(e -> System.out.printf("Length %d: %d words%n", e.getKey(), e.getValue())); 83 | } catch (IOException e) { 84 | e.printStackTrace(); 85 | } 86 | } 87 | 88 | public static void main(String[] args) { 89 | ProcessDictionary processDictionary = new ProcessDictionary(); 90 | processDictionary.printTenLongestWords(); 91 | processDictionary.printWordsOfEachLength(); 92 | processDictionary.printHowManyWordsOfEachLength(); 93 | processDictionary.printSortedMapOfWords(); 94 | processDictionary.printSortedMapOfWordsUsingBufferedReader(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | # Claude Development Documentation 2 | 3 | This document contains important information for Claude AI assistant when working on this project. 4 | 5 | ## Project Overview 6 | 7 | This is the source code repository for "Functional Modern Java" presentation examples. It's a Java project showcasing modern Java features and functional programming patterns, recently modernized with current tooling and testing frameworks. 8 | 9 | ## Build System & Dependencies 10 | 11 | ### Core Technologies 12 | - **Language**: Java 21 (using Gradle toolchain) 13 | - **Build Tool**: Gradle 8.14.2 (latest stable) 14 | - **Testing**: JUnit 5.13.2 (fully migrated from JUnit 4) 15 | - **CI**: GitHub Actions 16 | 17 | ### Key Dependencies 18 | - `org.junit.jupiter:junit-jupiter` - Main testing framework 19 | - `org.junit.platform:junit-platform-launcher` - Required for test execution 20 | - `com.google.code.gson:gson` - JSON processing library 21 | 22 | ### Dependency Management 23 | - Uses JUnit BOM for consistent version management 24 | - No JUnit vintage engine (fully migrated to JUnit 5) 25 | 26 | ## Project Structure 27 | 28 | ``` 29 | src/ 30 | ├── main/java/ # Main source code with Java examples 31 | ├── test/java/ # JUnit 5 test suite (16 test files) 32 | gradle/ 33 | └── wrapper/ # Gradle wrapper files 34 | ``` 35 | 36 | ## Recent Modernization Work 37 | 38 | ### Major Updates Completed 39 | 1. **Gradle Upgrade**: 7.6 → 8.14.2 40 | 2. **Java Version**: 11 → 21 (latest LTS with toolchain support) 41 | 3. **JUnit Management**: Added BOM for consistent versioning 42 | 4. **Build Modernization**: Updated GitHub Actions 43 | 44 | ### Testing Framework Status 45 | - **All test files already use JUnit 5** (16 files) 46 | - **Modern patterns in use**: 47 | - `assertThrows()` for exception testing 48 | - `@BeforeEach/@AfterEach` lifecycle methods 49 | - `@Disabled` for disabled tests 50 | - `org.junit.jupiter.api.Assertions.*` imports 51 | 52 | ## Common Development Tasks 53 | 54 | ### Running Tests 55 | ```bash 56 | # All tests 57 | ./gradlew test 58 | 59 | # Specific test class 60 | ./gradlew test --tests "http.JokeClientTest" 61 | 62 | # With detailed output 63 | ./gradlew test --info 64 | ``` 65 | 66 | ### Building 67 | ```bash 68 | # Clean build 69 | ./gradlew clean build 70 | 71 | # Just compile 72 | ./gradlew compileJava compileTestJava 73 | ``` 74 | 75 | ## Important Notes for Claude 76 | 77 | ### When Working with Tests 78 | - All tests use JUnit 5 - no JUnit 4 imports should be added 79 | - Use `assertThrows()` for exception testing, not `@Test(expected = ...)` 80 | - Use `@BeforeEach/@AfterEach` instead of `@Before/@After` 81 | - Use `@Disabled` instead of `@Ignore` 82 | 83 | ### Code Patterns to Follow 84 | - Java 21 features are available for build/test infrastructure 85 | - Code examples maintain compatibility with modern Java patterns 86 | - Use modern testing patterns (JUnit 5) 87 | - Follow existing package structure and naming conventions 88 | 89 | ### Dependencies 90 | - JUnit BOM manages version consistency 91 | - Avoid adding junit-vintage-engine unless absolutely necessary 92 | 93 | ### GitHub Actions 94 | - CI runs on Java 21 95 | - Builds with `./gradlew build` 96 | - All tests must pass for successful builds 97 | 98 | ## Known Issues/Considerations 99 | 100 | ### Test Execution 101 | - All core functionality tests pass consistently 102 | - Some deprecation warnings about `finalize()` method (expected with Java 21) 103 | 104 | ### Compatibility 105 | - Project uses Java 21 for builds and runtime 106 | - Modern Gradle version provides better performance and features 107 | - JUnit 5 provides better test organization and modern features 108 | 109 | ## Files to Monitor 110 | 111 | ### Critical Configuration Files 112 | - `build.gradle` - Main build configuration 113 | - `gradle/wrapper/gradle-wrapper.properties` - Gradle version 114 | - `.github/workflows/gradle.yml` - CI configuration 115 | 116 | ### Test Directory Structure 117 | - All test files in `src/test/java/` use JUnit 5 118 | - Test organization follows main source package structure 119 | - Both unit tests and integration examples present 120 | 121 | ## Test Files Inventory 122 | 123 | The project contains 16 test files covering: 124 | - `collections/` - Immutable collections tests 125 | - `generics/` - Generic type safety tests 126 | - `got/` - Member DAO tests 127 | - `http/` - HTTP client tests (Astro, Joke APIs) 128 | - `interfaces/` - Interface enhancement tests 129 | - `lambdas/` - Functional interface tests 130 | - `lvti/` - Local variable type inference tests 131 | - `optional/` - Optional handling tests 132 | - `streams/` - Stream API exercises and tests 133 | 134 | This documentation helps ensure consistent development practices and maintains the project's modernized state. -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /src/main/resources/dict/propernames: -------------------------------------------------------------------------------- 1 | Aaron 2 | Adam 3 | Adlai 4 | Adrian 5 | Agatha 6 | Ahmed 7 | Ahmet 8 | Aimee 9 | Al 10 | Alain 11 | Alan 12 | Alastair 13 | Albert 14 | Alberto 15 | Alejandro 16 | Alex 17 | Alexander 18 | Alexis 19 | Alf 20 | Alfred 21 | Alison 22 | Allan 23 | Allen 24 | Alvin 25 | Amanda 26 | Amarth 27 | Amedeo 28 | Ami 29 | Amigo 30 | Amir 31 | Amos 32 | Amy 33 | Anatole 34 | Anatoly 35 | Anderson 36 | Andre 37 | Andrea 38 | Andreas 39 | Andrew 40 | Andries 41 | Andy 42 | Angela 43 | Angus 44 | Anita 45 | Ann 46 | Anna 47 | Annard 48 | Anne 49 | Annie 50 | Anthony 51 | Anton 52 | Antonella 53 | Antonio 54 | Antony 55 | Archie 56 | Ariel 57 | Arlene 58 | Arne 59 | Arnold 60 | Art 61 | Arthur 62 | Audrey 63 | Avery 64 | Axel 65 | Barbara 66 | Barbra 67 | Barney 68 | Barrett 69 | Barrio 70 | Barry 71 | Bart 72 | Barton 73 | Bea 74 | Beckie 75 | Becky 76 | Belinda 77 | Ben 78 | Benjamin 79 | Benson 80 | Bernard 81 | Bernie 82 | Bert 83 | Bertrand 84 | Beth 85 | Betsy 86 | Betty 87 | Beverly 88 | Bill 89 | Billie 90 | Billy 91 | Bjorne 92 | Blaine 93 | Blair 94 | Blake 95 | Blayne 96 | Bob 97 | Bobbie 98 | Bobby 99 | Bonnie 100 | Boyce 101 | Boyd 102 | Brad 103 | Bradford 104 | Bradley 105 | Brandi 106 | Brandon 107 | Brandy 108 | Brenda 109 | Brendan 110 | Brender 111 | Brent 112 | Bret 113 | Brett 114 | Brian 115 | Briggs 116 | Brodie 117 | Brooke 118 | Bruce 119 | Bruno 120 | Bryan 121 | Bryce 122 | Bucky 123 | Bud 124 | Butler 125 | Byron 126 | Caleb 127 | Calvin 128 | Carisa 129 | Carl 130 | Carlo 131 | Carlos 132 | Carol 133 | Carole 134 | Caroline 135 | Carolyn 136 | Carsten 137 | Carter 138 | Cary 139 | Case 140 | Casey 141 | Casper 142 | Catherine 143 | Cathrin 144 | Cathryn 145 | Cathy 146 | Cecilia 147 | Celeste 148 | Celia 149 | Charleen 150 | Charlene 151 | Charles 152 | Charley 153 | Charlie 154 | Chet 155 | Chip 156 | Chris 157 | Christian 158 | Christie 159 | Christina 160 | Christofer 161 | Christophe 162 | Christopher 163 | Chuck 164 | Cindie 165 | Cindy 166 | Claire 167 | Clara 168 | Clare 169 | Clarence 170 | Clarissa 171 | Clark 172 | Claude 173 | Claudia 174 | Claudio 175 | Clay 176 | Clayton 177 | Clem 178 | Cliff 179 | Clifford 180 | Clyde 181 | Cole 182 | Coleen 183 | Colin 184 | Collin 185 | Connie 186 | Conrad 187 | Corey 188 | Cory 189 | Courtney 190 | Craig 191 | Cris 192 | Cristi 193 | Cristina 194 | Cristopher 195 | Curt 196 | Curtis 197 | Cynthia 198 | Cyrus 199 | Dale 200 | Dalton 201 | Damon 202 | Damone 203 | Dan 204 | Dana 205 | Dani 206 | Daniel 207 | Daniele 208 | Danielle 209 | Dannie 210 | Danny 211 | Darci 212 | Daren 213 | Darin 214 | Darrell 215 | Darren 216 | Darryl 217 | Daryl 218 | Dave 219 | David 220 | Dawn 221 | Dawson 222 | Dean 223 | Deb 224 | Debbie 225 | Debi 226 | Deborah 227 | Deirdre 228 | Del 229 | Delbert 230 | Denis 231 | Dennis 232 | Derek 233 | Devon 234 | Dewey 235 | Diana 236 | Diane 237 | Dick 238 | Dieter 239 | Dimetry 240 | Dimitry 241 | Dion 242 | Dirk 243 | Dominic 244 | Dominick 245 | Don 246 | Donal 247 | Donald 248 | Donn 249 | Donna 250 | Donne 251 | Donnie 252 | Donovan 253 | Dori 254 | Dorian 255 | Dorothy 256 | Dory 257 | Doug 258 | Douglas 259 | Doyle 260 | Drew 261 | Duane 262 | Duke 263 | Duncan 264 | Dustin 265 | Dwayne 266 | Dwight 267 | Dylan 268 | Earl 269 | Earle 270 | Earnie 271 | Ed 272 | Eddie 273 | Eddy 274 | Edgar 275 | Edith 276 | Edmond 277 | Edmund 278 | Eduardo 279 | Edward 280 | Edwin 281 | Eileen 282 | Elaine 283 | Eli 284 | Elias 285 | Elijah 286 | Eliot 287 | Elisabeth 288 | Elizabeth 289 | Ellen 290 | Elliot 291 | Elliott 292 | Elric 293 | Elsa 294 | Elvis 295 | Elwood 296 | Emil 297 | Emily 298 | Emma 299 | Emmett 300 | Eric 301 | Erick 302 | Erik 303 | Ernest 304 | Ernie 305 | Ernst 306 | Erwin 307 | Ethan 308 | Eugene 309 | Eva 310 | Evan 311 | Evelyn 312 | Everett 313 | Farouk 314 | Fay 315 | Felix 316 | Fletcher 317 | Floria 318 | Florian 319 | Floyd 320 | Frances 321 | Francis 322 | Francisco 323 | Francois 324 | Frank 325 | Franklin 326 | Fred 327 | Frederic 328 | Frederick 329 | Fritz 330 | Gabriel 331 | Gail 332 | Gale 333 | Galen 334 | Gary 335 | Gene 336 | Geoff 337 | Geoffrey 338 | George 339 | Gerald 340 | Gerard 341 | Gideon 342 | Gigi 343 | Gil 344 | Giles 345 | Gill 346 | Gilles 347 | Ginny 348 | Giovanni 349 | Glen 350 | Glenn 351 | Glynn 352 | Gordon 353 | Grace 354 | Graeme 355 | Graham 356 | Grant 357 | Granville 358 | Greg 359 | Gregg 360 | Gregge 361 | Gregor 362 | Gregory 363 | Gretchen 364 | Griff 365 | Guido 366 | Guillermo 367 | Gunnar 368 | Gunter 369 | Guy 370 | Gypsy 371 | Hal 372 | Hamilton 373 | Hank 374 | Hans 375 | Harmon 376 | Harold 377 | Harris 378 | Harry 379 | Hartmann 380 | Harv 381 | Harvey 382 | Hazel 383 | Heather 384 | Hector 385 | Heidi 386 | Hein 387 | Heinrich 388 | Heinz 389 | Helen 390 | Helge 391 | Henry 392 | Herb 393 | Herbert 394 | Herman 395 | Herve 396 | Hienz 397 | Hilda 398 | Hillary 399 | Hillel 400 | Himawan 401 | Hirofumi 402 | Hirotoshi 403 | Hiroyuki 404 | Hitoshi 405 | Hohn 406 | Holly 407 | Hon 408 | Honzo 409 | Horst 410 | Hotta 411 | Howard 412 | Hsi 413 | Hsuan 414 | Huashi 415 | Hubert 416 | Huey 417 | Hugh 418 | Hughes 419 | Hui 420 | Hume 421 | Hunter 422 | Hurf 423 | Hwa 424 | Hy 425 | Ian 426 | Ilya 427 | Ima 428 | Indra 429 | Ira 430 | Irfan 431 | Irvin 432 | Irving 433 | Irwin 434 | Isaac 435 | Isabelle 436 | Isidore 437 | Israel 438 | Izchak 439 | Izumi 440 | Izzy 441 | Jack 442 | Jackye 443 | Jacob 444 | Jacobson 445 | Jacques 446 | Jagath 447 | Jaime 448 | Jakob 449 | James 450 | Jamie 451 | Jan 452 | Jane 453 | Janet 454 | Janice 455 | Janos 456 | Jared 457 | Jarl 458 | Jarmo 459 | Jarvis 460 | Jason 461 | Jay 462 | Jayant 463 | Jayesh 464 | Jean 465 | Jean-Christophe 466 | Jean-Pierre 467 | Jeanette 468 | Jeanne 469 | Jeannette 470 | Jeannie 471 | Jeany 472 | Jef 473 | Jeff 474 | Jeffery 475 | Jeffie 476 | Jeffrey 477 | Jelske 478 | Jem 479 | Jenine 480 | Jennie 481 | Jennifer 482 | Jerald 483 | Jeremy 484 | Jerome 485 | Jerrie 486 | Jerry 487 | Jesper 488 | Jess 489 | Jesse 490 | Jesus 491 | Ji 492 | Jianyun 493 | Jill 494 | Jim 495 | Jimmy 496 | Jin 497 | Jinchao 498 | Jingbai 499 | Jinny 500 | Jiri 501 | Jisheng 502 | Jitendra 503 | Joachim 504 | Joanne 505 | Jochen 506 | Jock 507 | Joe 508 | Joel 509 | Johan 510 | Johann 511 | John 512 | Johnathan 513 | Johnnie 514 | Johnny 515 | Jon 516 | Jonathan 517 | Jones 518 | Jong 519 | Joni 520 | Joon 521 | Jordan 522 | Jorge 523 | Jos 524 | Jose 525 | Joseph 526 | Josh 527 | Joshua 528 | Josip 529 | Joubert 530 | Joyce 531 | Juan 532 | Judge 533 | Judith 534 | Judy 535 | Juergen 536 | Juha 537 | Julia 538 | Julian 539 | Juliane 540 | Julianto 541 | Julie 542 | Juliet 543 | Julius 544 | Jun 545 | June 546 | Jurevis 547 | Juri 548 | Jussi 549 | Justin 550 | Jwahar 551 | Kaj 552 | Kamel 553 | Kamiya 554 | Kanthan 555 | Karen 556 | Kari 557 | Karl 558 | Kate 559 | Kathleen 560 | Kathryn 561 | Kathy 562 | Kay 563 | Kayvan 564 | Kazuhiro 565 | Kee 566 | Kees 567 | Keith 568 | Kelly 569 | Kelvin 570 | Kemal 571 | Ken 572 | Kenn 573 | Kenneth 574 | Kent 575 | Kenton 576 | Kerri 577 | Kerry 578 | Kevan 579 | Kevin 580 | Kevyn 581 | Kieran 582 | Kiki 583 | Kikki 584 | Kim 585 | Kimberly 586 | Kimmo 587 | Kinch 588 | King 589 | Kirk 590 | Kirsten 591 | Kit 592 | Kitty 593 | Klaudia 594 | Klaus 595 | Knapper 596 | Knudsen 597 | Knut 598 | Knute 599 | Kolkka 600 | Konrad 601 | Konstantinos 602 | Kory 603 | Kris 604 | Kristen 605 | Kristi 606 | Kristian 607 | Kristin 608 | Kriton 609 | Krzysztof 610 | Kuldip 611 | Kurt 612 | Kusum 613 | Kyle 614 | Kylo 615 | Kyu 616 | Kyung 617 | Lana 618 | Lance 619 | Lanny 620 | Lar 621 | Larry 622 | Lars 623 | Laura 624 | Laurel 625 | Laurence 626 | Laurent 627 | Laurianne 628 | Laurie 629 | Lawrence 630 | Lea 631 | Leads 632 | Lee 633 | Leif 634 | Leigh 635 | Leila 636 | Leith 637 | Len 638 | Lenny 639 | Lenora 640 | Leo 641 | Leon 642 | Leonard 643 | Leora 644 | Les 645 | Leslie 646 | Lester 647 | Leung 648 | Lewis 649 | Lex 650 | Liber 651 | Lievaart 652 | Lila 653 | Lin 654 | Linda 655 | Linder 656 | Lindsay 657 | Lindsey 658 | Linley 659 | Lisa 660 | List 661 | Liyuan 662 | Liz 663 | Liza 664 | Lloyd 665 | Lois 666 | Lonhyn 667 | Lord 668 | Loren 669 | Lorenzo 670 | Lori 671 | Lorien 672 | Lorraine 673 | Lou 674 | Louie 675 | Louiqa 676 | Louis 677 | Louise 678 | Loukas 679 | Lowell 680 | Loyd 681 | Luc 682 | Lucifer 683 | Lucius 684 | Lui 685 | Luis 686 | Lukas 687 | Luke 688 | Lum 689 | Lyndon 690 | Lynn 691 | Lynne 692 | Lynnette 693 | Maarten 694 | Mac 695 | Magnus 696 | Mah 697 | Mahesh 698 | Mahmoud 699 | Major 700 | Malaclypse 701 | Malcolm 702 | Malloy 703 | Malus 704 | Manavendra 705 | Manjeri 706 | Mann 707 | Manny 708 | Manolis 709 | Manuel 710 | Mara 711 | Marc 712 | Marcel 713 | Marci 714 | Marcia 715 | Marco 716 | Marcos 717 | Marek 718 | Margaret 719 | Margie 720 | Margot 721 | Marguerite 722 | Maria 723 | Marian 724 | Marie 725 | Marilyn 726 | Mario 727 | Marion 728 | Mariou 729 | Mark 730 | Markus 731 | Marla 732 | Marlena 733 | Marnix 734 | Marsh 735 | Marsha 736 | Marshall 737 | Martha 738 | Martin 739 | Marty 740 | Martyn 741 | Marvin 742 | Mary 743 | Masanao 744 | Masanobu 745 | Mason 746 | Mat 747 | Mats 748 | Matt 749 | Matthew 750 | Matthias 751 | Matthieu 752 | Matti 753 | Maureen 754 | Maurice 755 | Max 756 | Mayo 757 | Mechael 758 | Meehan 759 | Meeks 760 | Mehrdad 761 | Melinda 762 | Merat 763 | Merril 764 | Merton 765 | Metin 766 | Micah 767 | Michael 768 | Micheal 769 | Michel 770 | Michelle 771 | Michiel 772 | Mick 773 | Mickey 774 | Micky 775 | Miek 776 | Mikael 777 | Mike 778 | Mikey 779 | Miki 780 | Miles 781 | Milner 782 | Milo 783 | Miltos 784 | Miriam 785 | Miriamne 786 | Mitch 787 | Mitchell 788 | Moe 789 | Mohammad 790 | Molly 791 | Mongo 792 | Monica 793 | Monty 794 | Moore 795 | Moran 796 | Morgan 797 | Morris 798 | Morton 799 | Moses 800 | Mosur 801 | Mott 802 | Murat 803 | Murph 804 | Murray 805 | Murthy 806 | Mwa 807 | Myrick 808 | Myron 809 | Mysore 810 | Nadeem 811 | Naim 812 | Nancy 813 | Nanda 814 | Naomi 815 | Naoto 816 | Naren 817 | Narendra 818 | Naresh 819 | Nate 820 | Nathan 821 | Nathaniel 822 | Natraj 823 | Neal 824 | Ned 825 | Neil 826 | Nelken 827 | Neville 828 | Nguyen 829 | Nhan 830 | Niall 831 | Nichael 832 | Nicholas 833 | Nici 834 | Nick 835 | Nicolas 836 | Nicolette 837 | Nicolo 838 | Niels 839 | Nigel 840 | Nikolai 841 | Nils 842 | Ning 843 | Ninja 844 | No 845 | Noam 846 | Noemi 847 | Nora 848 | Norbert 849 | Norm 850 | Norma 851 | Norman 852 | Nou 853 | Novo 854 | Novorolsky 855 | Ofer 856 | Olaf 857 | Old 858 | Ole 859 | Oleg 860 | Oliver 861 | Olivier 862 | Olof 863 | Olson 864 | Omar 865 | Orville 866 | Oscar 867 | Oskar 868 | Owen 869 | Ozan 870 | Pablo 871 | Page 872 | Pam 873 | Pamela 874 | Panacea 875 | Pandora 876 | Panos 877 | Pantelis 878 | Panzer 879 | Paola 880 | Part 881 | Pascal 882 | Pat 883 | Patrice 884 | Patricia 885 | Patricio 886 | Patrick 887 | Patty 888 | Paul 889 | Paula 890 | Pedro 891 | Peggy 892 | Penny 893 | Per 894 | Perry 895 | Pete 896 | Peter 897 | Petr 898 | Phil 899 | Philip 900 | Philippe 901 | Phill 902 | Phillip 903 | Phiroze 904 | Pia 905 | Piercarlo 906 | Pierce 907 | Pierette 908 | Pierre 909 | Piet 910 | Piete 911 | Pieter 912 | Pilar 913 | Pilot 914 | Pim 915 | Ping 916 | Piotr 917 | Pitawas 918 | Plastic 919 | Po 920 | Polly 921 | Pontus 922 | Pradeep 923 | Prakash 924 | Pratap 925 | Pratapwant 926 | Pratt 927 | Pravin 928 | Presley 929 | Pria 930 | Price 931 | Raanan 932 | Rabin 933 | Radek 934 | Rafael 935 | Rafik 936 | Raghu 937 | Ragnar 938 | Rahul 939 | Raif 940 | Rainer 941 | Raj 942 | Raja 943 | Rajarshi 944 | Rajeev 945 | Rajendra 946 | Rajesh 947 | Rajiv 948 | Rakhal 949 | Ralf 950 | Ralph 951 | Ram 952 | Ramadoss 953 | Raman 954 | Ramanan 955 | Ramesh 956 | Ramiro 957 | Ramneek 958 | Ramon 959 | Ramsey 960 | Rand 961 | Randal 962 | Randall 963 | Randell 964 | Randolph 965 | Randy 966 | Ranjit 967 | Raphael 968 | Rathnakumar 969 | Raul 970 | Ravi 971 | Ravindran 972 | Ravindranath 973 | Ray 974 | Rayan 975 | Raymond 976 | Real 977 | Rebecca 978 | Rees 979 | Reid 980 | Reiner 981 | Reinhard 982 | Renu 983 | Revised 984 | Rex 985 | Rhonda 986 | Ric 987 | Ricardo 988 | Rich 989 | Richard 990 | Rick 991 | Ricky 992 | Rik 993 | Ritalynne 994 | Ritchey 995 | Ro 996 | Rob 997 | Robbin 998 | Robert 999 | Roberta 1000 | Roberto 1001 | Robin 1002 | Rod 1003 | Rodent 1004 | Roderick 1005 | Rodger 1006 | Rodney 1007 | Roger 1008 | Rogue 1009 | Roland 1010 | Rolf 1011 | Rolfe 1012 | Romain 1013 | Roman 1014 | Ron 1015 | Ronald 1016 | Ronni 1017 | Root 1018 | Ross 1019 | Roxana 1020 | Roxane 1021 | Roxanne 1022 | Roxie 1023 | Roy 1024 | Rudolf 1025 | Rudolph 1026 | Rudy 1027 | Rupert 1028 | Russ 1029 | Russell 1030 | Rusty 1031 | Ruth 1032 | Saad 1033 | Sabrina 1034 | Saify 1035 | Saiid 1036 | Sal 1037 | Sally 1038 | Sam 1039 | Samir 1040 | Samuel 1041 | Sanand 1042 | Sanche 1043 | Sandeep 1044 | Sandip 1045 | Sandra 1046 | Sandy 1047 | Sanford 1048 | Sangho 1049 | Sanity 1050 | Sanjay 1051 | Sanjeev 1052 | Sanjib 1053 | Santa 1054 | Saqib 1055 | Sarah 1056 | Sassan 1057 | Saul 1058 | Saumya 1059 | Scot 1060 | Scott 1061 | Sean 1062 | Sedat 1063 | Sedovic 1064 | Seenu 1065 | Sehyo 1066 | Sekar 1067 | Serdar 1068 | Sergeant 1069 | Sergei 1070 | Sergio 1071 | Sergiu 1072 | Seth 1073 | Seymour 1074 | Shadow 1075 | Shahid 1076 | Shai 1077 | Shakil 1078 | Shamim 1079 | Shane 1080 | Shankar 1081 | Shannon 1082 | Sharada 1083 | Sharan 1084 | Shari 1085 | Sharon 1086 | Shatter 1087 | Shaw 1088 | Shawn 1089 | Shean 1090 | Sheila 1091 | Shel 1092 | Sherman 1093 | Sherri 1094 | Shirley 1095 | Sho 1096 | Shutoku 1097 | Shuvra 1098 | Shyam 1099 | Sid 1100 | Sidney 1101 | Siegurd 1102 | Sigurd 1103 | Simon 1104 | Siping 1105 | Sir 1106 | Sjaak 1107 | Sjouke 1108 | Skeeter 1109 | Skef 1110 | Skip 1111 | Slartibartfast 1112 | Socorrito 1113 | Sofia 1114 | Sofoklis 1115 | Son 1116 | Sonja 1117 | Sonny 1118 | Soohong 1119 | Sorrel 1120 | Space 1121 | Spass 1122 | Spencer 1123 | Spike 1124 | Spock 1125 | Spudboy 1126 | Spy 1127 | Spyros 1128 | Sri 1129 | Sridhar 1130 | Sridharan 1131 | Srikanth 1132 | Srinivas 1133 | Srinivasan 1134 | Sriram 1135 | Srivatsan 1136 | Ssi 1137 | Stacey 1138 | Stacy 1139 | Stagger 1140 | Stan 1141 | Stanislaw 1142 | Stanley 1143 | Stanly 1144 | Starbuck 1145 | Steen 1146 | Stefan 1147 | Stephan 1148 | Stephanie 1149 | Stephe 1150 | Stephen 1151 | Stevan 1152 | Steve 1153 | Steven 1154 | Stewart 1155 | Straka 1156 | Stu 1157 | Stuart 1158 | Subra 1159 | Sue 1160 | Sugih 1161 | Sumitro 1162 | Sundar 1163 | Sundaresan 1164 | Sunil 1165 | Suresh 1166 | Surya 1167 | Susan 1168 | Susanne 1169 | Susumu 1170 | Suu 1171 | Suwandi 1172 | Suyog 1173 | Suzan 1174 | Suzanne 1175 | Svante 1176 | Swamy 1177 | Syd 1178 | Syed 1179 | Sylvan 1180 | Syun 1181 | Tad 1182 | Tahsin 1183 | Tai 1184 | Tait 1185 | Takao 1186 | Takayuki 1187 | Takeuchi 1188 | Tal 1189 | Tammy 1190 | Tanaka 1191 | Tandy 1192 | Tanya 1193 | Tao 1194 | Tareq 1195 | Tarmi 1196 | Taurus 1197 | Ted 1198 | Teresa 1199 | Teri 1200 | Teriann 1201 | Terrance 1202 | Terrence 1203 | Terri 1204 | Terry 1205 | Teruyuki 1206 | Thad 1207 | Tharen 1208 | The 1209 | Theo 1210 | Theodore 1211 | Thierry 1212 | Think 1213 | Thomas 1214 | Those 1215 | Thuan 1216 | Ti 1217 | Tiefenthal 1218 | Tigger 1219 | Tim 1220 | Timo 1221 | Timothy 1222 | Tobias 1223 | Toby 1224 | Todd 1225 | Toerless 1226 | Toft 1227 | Tolerant 1228 | Tollefsen 1229 | Tom 1230 | Tomas 1231 | Tommy 1232 | Tony 1233 | Tor 1234 | Torsten 1235 | Toufic 1236 | Tovah 1237 | Tracey 1238 | Tracy 1239 | Tran 1240 | Travis 1241 | Trent 1242 | Trevor 1243 | Trey 1244 | Triantaphyllos 1245 | Tricia 1246 | Troy 1247 | Trying 1248 | Tuan 1249 | Tuna 1250 | Turkeer 1251 | Tyler 1252 | Uri 1253 | Urs 1254 | Vadim 1255 | Val 1256 | Valentin 1257 | Valeria 1258 | Valerie 1259 | Van 1260 | Vance 1261 | Varda 1262 | Vassos 1263 | Vaughn 1264 | Venkata 1265 | Vern 1266 | Vernon 1267 | Vic 1268 | Vice 1269 | Vick 1270 | Vicki 1271 | Vickie 1272 | Vicky 1273 | Victor 1274 | Victoria 1275 | Vidhyanath 1276 | Vijay 1277 | Vilhelm 1278 | Vince 1279 | Vincent 1280 | Vincenzo 1281 | Vinod 1282 | Vishal 1283 | Vistlik 1284 | Vivek 1285 | Vladimir 1286 | Vladislav 1287 | Wade 1288 | Walt 1289 | Walter 1290 | Warren 1291 | Wayne 1292 | Wendell 1293 | Wendi 1294 | Wendy 1295 | Werner 1296 | Wes 1297 | Will 1298 | William 1299 | Willie 1300 | Wilmer 1301 | Wilson 1302 | Win 1303 | Winnie 1304 | Winston 1305 | Wolf 1306 | Wolfgang 1307 | Woody 1308 | Yvonne 1309 | --------------------------------------------------------------------------------