# modern-java-recipe

# The Basics

  • Lambda Expressions
  • Method References
  • Constructor References ( a special case of Method Reference )
  • Functional Interfaces
  • Default Methods in Interfaces
  • Static Methods in Interfaces

# The java.util.function Package

  • Consumer
  • Supplier
  • Predicate
  • Function

# Streams

  • Creating Streams
    • Stream.of
    • Stream.iterate
    • Stream.generate
    • Arrays.stream
    • Collection.stream
    • IntStream.range IntStream.rangeClosed
  • Boxed Streams
    • IntStream.boxed
    • IntStream.mapToObj
  • Reduction Oprations Using Reduce
    • reduce
    • count
    • max
    • min
    • average
    • collect
  • Check Sorting Using Reduce ( BinaryOperator assert and return current )
  • Debugging Streams with peek ( peek intermediate operation)
  • Converting Strings to Streams and Back
public static boolean isPalindrome(String s) {
    String forward = s.toLowerCase().codePoints().filter(Character::isLetterOrDigit).collect(
            StringBuilder::new,
            StringBuilder::appendCodePoint,
            StringBuilder::append
    ).toString();

    String backward = new StringBuilder(forward).reverse().toString();

    return forward.equals(backward);
}
  • Counting Elements
    • count terminal operator
    • Collectors.counting()
  • Summary Statistics ( summaryStatistics terminal operator )
  • Finding the first Element in a Stream ( findFirst findAny )
  • Using anyMatch allMatch noneMatch
  • Stream flatMap Versus map ( use flatMap to flatten substream into one stream )
  • Concatenating Streams ( using static method Stream.concat to concat 2 streams )
  • Lazy Streams ( streams are already lazy )

# Comparators and Collectors

  • Sorting using a Comparator
  • Converting a Stream into a Collection ( toList toSet toCollection )
  • Adding a Linear Collection to a Map ( Function.identity )
  • Sorting Maps ( Map.Entry.comparingByKey Map.Entry.comparingByValue )
  • Partitioning and Grouping
  • Downstream Collectors
  • Finding Max and Min Values
    • max terminal operator
    • min terminal operator
    • Collectors.maxBy
    • Collectors.minBy
  • Creading Immutable Collections
public final <T> List<T> createImmutableList(T... elements){
    return Arrays.stream(elements).collect(Collectors.toUnmodifiableList());
}

public final <T> Set<T> createImmutableSet(T... elements){
    return Arrays.stream(elements).collect(Collectors.toUnmodifiableSet());
}
  • Implementing the Collector Interface

# Issues with Streams, Lambdas, and Method References

  • The java.util.Objects Class ( some useful utility method)
    • requireNotNull
    • isNull
    • nonNull
  • Lambdas and Effectively Final
  • Streams of Random Numbers ( Use the static ints, longs and doubles methods in java.util.Random )
  • Default Methods in Map
    • computeIfAbsent
    • computeIfPresent
    • forEach
    • getOrDefault
    • merge
    • putIfAbsent
    • remove
    • replace
    • replaceAll
  • Default Method Conflict
    • In any conflict between a method in a class and a default method in an interface, the class always wins.
    • If the conflict comes between two interfaces where one is a descendant of the other, then the descendant wins, the same way they do in classes
    • If there is no inheritance relationship between the two defaults, the class will not compile
  • Iterating Over Collections and Maps ( forEach method )
  • Logging with a Supplier
  • Closure Composition
    • compose in Function
    • andThen in Function
    • andThen in Consumer
    • and in Predicate
    • or in Predicate
    • negate in Predicate

# The Optional Type

  • Creating an Optional
    • Optional.empty
    • Optional.of
    • Optional.ofNullable
  • Retrieving Values from an Optional
    • get
    • ifPresent
    • orElse
    • orElseGet
    • orElseThrow
  • Optional in Getters and Setters ( wrap the result of getter methods in Optionals, but don't do the same for setters ) ( not follow javabean convention )
  • Optional flatMap Versus map ( use flatMap to avoid wrapping an Optional inside another Optional )
  • Mapping Optional ( map and stream )

# File I/O

  • Process Files ( use the static lines method in java.nio.file.Files to return the contents of a file as a stream )
  • Retrieving Files as a Stream ( Use the static Files.list method to return Path as a stream )
  • Walking the Filesystem ( use the static Files.walk to perform a depth-first traversal of the filesystem )
  • Searching the Filesystem ( use the static Files.find method )

# The java.time Package

  • Using the Basic Date-Time Classes
    • Instant
    • Duration
    • Period
    • LocalDate
    • LocalTime
    • LocalDateTime
    • ZonedDateTime
  • Creating Dates and Times from Existing Instances (use plus minus with method )
  • Parsing and Formatting ( DateTimeFormatter )
LocalDateTime now = LocalDateTime.now();
String textNow = now.format(DateTimeFormatter.ISO_DATE_TIME);

LocalDateTime dateTime = LocalDateTime.parse(textNow,DateTimeFormatter.ISO_DATE_TIME);

# Parallelism and Concurrency

Concurrency is when multiple tasks can run in overlapping time periods

Parallelism is when multiple tasks run at literally the same time

  • Converting from Sequential to Parallel Streams
List<Integer> numbers = Arrays.asList(1,3,5,7,9);

boolean isParallel = numbers.parallelStream().isParallel();
boolean alsoIsParallel = numbers.stream().parallel().isParallel();
  • WWhen Parallel helps
    • A large amount of data , or
    • A time-consuming process for each element, and
    • A source of data that is easy to divide ( LinkedList, Stream.iterate are hard to split ) , and
    • Operations that are stateless and associative ( order doesn't matter )
  • The Future Interface
ExecutorService service = Executors.newCachedThreadPool();

Future<String> future = service.submit(()->{
    Thread.sleep(1000);
    return "Hello World";
});

System.out.println("processing");

try{
    if(!future.isCancelled()){
        System.out.println(future.get()); // blocking call
    }else{
        System.out.println("Cancelled");
    }
}catch (InterruptedException | ExecutionException e){
    e.printStackTrace();
}
  • Completing a CompletableFuture
CompletableFuture<String> future1 = new CompletableFuture<>();
future1.complete("str1");

CompletableFuture<String> future2 = CompletableFuture.completedFuture("str2"); // like Promise.resolve

CompletableFuture<String> future3 = CompletableFuture.supplyAsync(()->"str3"); // like new Promise((resolve)=>resolve("str3"))
  • Coodinating CompletableFutures ( use thenApply thenCompose thenRun to trigger another action ater completion of one Future )