This is the first day of my participation in the Gwen Challenge in November. Check out the details: the last Gwen Challenge in 2021

Read Java in Action to systematically review the new Java8 features, such as lambda expressions, method references, streams, default methods, Optional, CompletableFuture, etc. This article is the summary of the first two chapters.

1. Basic concepts

1.1 stream processing

  • Java8 provides a Stream API that supports parallel operations of multiple data processes. The idea is to describe requirements from a high-level perspective, while the “implementation” (Stream library) chooses the underlying best execution mechanism.
  • The production and processing of the collection constitute abstract encapsulation, such as loop iteration directly carried out by the library inside, use without entangling the loop process.
  • Provides encapsulated parallel processing capabilities based on divide-and-conquer + shared-nothing mutable state.

1.2 Method References &Lambda- Anonymous functions

  • Method reference: Analogous to an object reference, passing a method as an equivalent (executable argument).

  • Lambda: Pass the function as an equivalent.

1.3 Default interface methods

Let the interface support declare the default implementation of the interface method. The default method in the interface will be called only if the interface with the default method is not implemented in the class.

1.4 Java Modularization

  • Solve a problem:
    • Jar-based Java packages have no declared structure and are not suitable for componentized builds.
    • In iterative evolution, when an interface changes, all classes that implement that interface change
  • Treatment:
    • Java9 supports syntactically defining modules composed of a series of packages for better control over namespaces and package visibility.
    • The introduction of default methods for interfaces allows the interface to evolve continuously without affecting all classes that implement the interface.

1.5 Other Contents

  • Optional handles null issues
  • Pattern matching

2. Parameterized evolution of behavior

Definition:

A method can take multiple different behaviors as parameters and use them internally to accomplish different behaviors.

Evolution Scenario:

Filter apples by their color or weight properties.

Version 1: Traditional implementation
    // Version 1: Direct iterative filtering
    public static List<Apple> filterApples(List<Apple> inventory,Color color){
        List<Apple> filterApples = new ArrayList<>();
        for(Apple apple:inventory){
            if(color.equals(apple.getColor())){ filterApples.add(apple); }}return filterApples;
    }
Copy the code
Version 2: Implement behavior parameterization based on behavior interface + concrete implementation class
    // Version 2: Policy pattern based on interface + implementation class, encapsulating method policy with object
    public static List<Apple> filterApples(List<Apple> inventory,ApplePredicate predicate){
        List<Apple> filterApples = new ArrayList<>();
        for(Apple apple:inventory){
            if(predicate.test(apple)){ filterApples.add(apple); }}return filterApples;
    }
    // Behavior interface
    interface ApplePredicate {
        public boolean test(Apple a);
    }
    // Behavior parameterized object: red apple judgment
    class AppleRedPredicate implements ApplePredicate{
        @Override
        public boolean test(Apple a) {
            returnColor.RED.equals(a.getColor()); }}// Behavior parameterized object: red apple judgment
    class AppleHeavyWeightPredicate implements ApplePredicate{
        @Override
        public boolean test(Apple a) {
            return a.getWeight()>150; }}Copy the code
Version 3: Simplified number of classes based on anonymous classes
// Version 3: Based on anonymous classes
List<Apple> redApples3 = filterApples(inventory, new ApplePredicate() {
    @Override
    public boolean test(Apple a) {
        returnColor.RED.equals(a.getColor()); }});Copy the code
Version 4: Replace anonymous classes with lambda
// Version 4: Lambda simplifies anonymous classes
List<Apple> result = filterApples(inventory,(Apple a) -> Color.RED.equals(a.getColor()));
Copy the code
Version 5: Abstract the List type (reuse the filtering behavior)
    // Version 5: Type abstraction (introduces type parameters)
    interface Predicate<T>{
        boolean test(T t);
    }
    // Generalize the filter function
    static <T> List<T> filter(List<T> list,Predicate<T> p){
        List<T> result = new ArrayList<T>();
        for(T e:list){
            if(p.test(e)){ result.add(e); }}return result;
    }
	// An example
    List<Apple> result2 = filter(inventory,(Apple a) -> a.getWeight()>500);
    System.out.println(result2);
    // Filter even numbers
    Integer[] arrInt = {1.2.3.4.5.6};
    System.out.println(filter(Arrays.asList(arrInt),(Integer i) -> i%2= =0));
Copy the code

Complete sample code

Conclusion:

  • Core: A method takes multiple different behaviors as parameters and uses it internally to accomplish different capabilities.
  • Objective scenarios: adapt to changing requirements, parameterize different behaviors, reduce hard coding, adapt to changing conditions of sorting & filtering rules, threads, etc.
  • Whereas Java8 used anonymous classes to handle the problem of creating a large number of class implementations, java8 has since built on lambda implementations