Java8 was launched in 2014, all day long crying 8 version stability, enterprises are using JDK8, the result of the 8 features now system learning, sin! This series of 3-4 blog posts will give you a comprehensive overview of the new java8 features.

In fact, WHEN I read some entry-level blogs, I always worry about incomplete writing, so I hope that I can write a technical blog must be as complete as possible to sum up, so that I can read one entry level.

Lambda Quick Experience

The quickest way to get started is to watch the demo. Now there is a requirement for you to pick out the red apple among the many apples

  • Apple’s class

    public class Apple {
        String color;
        int weight;
    	// omit the constructor, get method
    }
    Copy the code

Method 1:

public static List<Apple> filterGreenAppleWithNormal(List<Apple> apples) {
    List<Apple> res = new ArrayList<>();
    for (Apple apple : apples) {
        if ("red".equals(apple.getColor())) { res.add(apple); }}return res;
}

/ / call
List<Apple> normal = filterGreenAppleWithNormal(apples);
Copy the code

If I had another requirement to pick out the green apples, this way I would create a new class, and then I would just change “red” to “green” and nothing else would change, which obviously doesn’t show up. So you can pass in the color as an argument

Method 2:

public static List<Apple> filterGreenAppleWithArg(List<Apple> apples, String color) {
    List<Apple> res = new ArrayList<>();
    for (Apple apple : apples) {
        if(color.equals(apple.getColor())) { res.add(apple); }}return res;
}

/ / call
List<Apple> arg = filterGreenAppleWithArg(apples, "red");
Copy the code

Now we have another requirement, we need to filter out apples of a certain weight or a certain color, and what do we do? The idea is to stack all the properties you can think of into the parameters of the method.

public static List<Apple> filterWeightOrColorWithArg(List<Apple> apples, String color, int weight, boolean flag) {
    List<Apple> res = new ArrayList<>();

    for (Apple apple : apples) {
        if (flag && color.equals(apple.getColor()) || !flag && apple.getWeight() > weight) {
            res.add(apple);
        }
    }
    return res;
}

/ / call
List<Apple> weightOrColor = filterWeightOrColorWithArg(apples, "".500.false);
Copy the code

Can I write it like that? Of course it solves the problem, but what if I have 5 properties, what if I have 6 properties, and what does flag mean in the argument.

If you think about it, screening for color, screening for weight, all of this is essentially screening, is a behavior, and it can be abstracted as an interface.

  • Behavior interface
public interface AppleFilter {
    boolean filter(Apple apple);
}
Copy the code

Method 3:

You first need to implement the interface to externalize the behavior

  • Filter the red Apple implementation class
public class RedFilter implements AppleFilter {
    @Override
    public boolean filter(Apple apple) {
        return "red".equals(apple.getColor()); }}Copy the code

Go back to using

public static List<Apple> filterApples(List<Apple> apples, AppleFilter filter) {
    List<Apple> res = new ArrayList<>();

    for (Apple apple : apples) {
        if(filter.filter(apple)) { res.add(apple); }}return res;
}

/ / call
List<Apple> behavior = filterApples(apples, new GreenFilter());
Copy the code

When there is a new requirement, just add another class. For example, if the requirement is to screen apples weighing more than 200G, just create a new filter class to implement the above interface.

public class WeightGt200Filter implements AppleFilter {
    @Override
    public boolean filter(Apple apple) {
        return apple.getWeight() > 200; }}Copy the code

How else can you simplify code? For those of you familiar with Java, anonymous inner classes come to mind

Method 4:

List<Apple> innerClass = filterApples(apples, new AppleFilter() {
    @Override
    public boolean filter(Apple apple) {
        return "green".equals(apple.getColor()); }});Copy the code

Generally at this point, a good IDE will start advising

And that brings us to our focus today, lambda expressions

Method 5:

List<Apple> lambda = filterApples(apples, apple -> apple.getWeight() > 500);
Copy the code

Yes, it is, but the filterApples method should not be omitted, but it is much more extensible than 1,2, and much more concise than 3,4

What is a lambda

You can think of a Lamdba expression as a succinct representation of an anonymous function that is transitive: it has no name, but it has a list of arguments, a function topic, a return type, and perhaps a list of exceptions that can be thrown

Writing format: (parameter) -> {body}

(apple) -> {apple.getweight () > 500; }

  • Lambda expressions can automatically infer types for arguments and, of course, show written types
  • There is no return statement because there is already an implied return
  • Lambda can have multiple lines of statements

Use cases:

  • () - > {}

  • () -> "java"

  • () -> {return "java"; }

  • (int a, int b) -> a * b

  • () -> {System.out.println("hello"); System.out.println("java"); }

How can I use lambda

Lambda expressions can only be used when using functional interfaces

A functional interface simply defines an abstract method, such as an AppleFilter interface that initially abstracts the behavior into a single filter() method. Note that there is only one abstract method, not just one method. In layman’s terms, classes that inherit the interface only need to implement one method.

The two most common interfaces are Comparator and Runnable

Later, in order to make it easier to distinguish functional interfaces, the Java API added a @funtionalInterface annotation. This annotation merely indicates that the class is a functional interface (it is not required). If you declare two abstract methods with this annotation, you will get an error

Java.util. Function provides four common functional interfaces

There are four commonly used functional interfaces for java.util.function: Function, Predicate, Consumer, and Predicate

These functional interfaces also depend on how the interface is declared, so here’s the Predicate interface, which basically does some work on the object that’s passed in and then returns a Boolean. Does that sound familiar? Yes, it’s like sifting through apples

  • predicateDemo
public static List<Apple> predicateDemo(List<Apple> apples, Predicate<Apple> predicate) {
    List<Apple> res = new ArrayList<>();
    for (Apple apple : apples) {
        if(predicate.test(apple)) { res.add(apple); }}return res;
}

/ / call
List<Apple> predicate = predicateDemo(apples, apple -> "green".equals(apple.getColor()));
Copy the code

The same goes for everything else, talent

  • functionDemo
public static List<Integer> functionDemo(List<Integer> nums, Function<Integer, Integer> function) {
    List<Integer> res = new ArrayList<>();
    for (int num : nums) {
        res.add(function.apply(num));
    }
    return res;
}

/ / call
List<Integer> function = functionDemo(Arrays.asList(1.8.7.3.9.2), (num) -> num * 2);
Copy the code
  • consumerDemo
public static void consumerDemo(List<Integer> list, Consumer<Integer> consumer) {
    for (intnum : list) { consumer.accept(num); }}/ / call
consumerDemo(Arrays.asList(1.5.6), (num) -> System.out.println(num));
consumerDemo(Arrays.asList(1.5.6), System.out::println);
Copy the code
  • supplierDemo
public static void supplierDemo(List<Integer> nums, Supplier<String> supplier) {
    StringBuilder sb = new StringBuilder();
    for (int num : nums) {
        sb.append(num).append(supplier.get());
    }
    System.out.println(sb);
}

/ / call
supplierDemo(Arrays.asList(1.5.6), () - >"java");
Copy the code

Method references

Is lambda the simplest way to write lambda? No, it’s not. And the simplest way to write lambda is to use method references

There are three main types of method references:

  • A method reference to a static method
Comparator<Integer> normalComparator = (a, b) -> a.compareTo(b);
Comparator<Integer> referenceComparator = Integer::compareTo;
Copy the code
  • A method reference to an instance method of any type
Function<String, Integer> normalFunction = (str) -> str.length();
Function<String, Integer> referenceFunction = String::length;

BiPredicate<List<String>, String> normalPredicate = (strings, str) -> strings.contains(str);
BiPredicate<List<String>, String> referencePredicate = List::contains;
Copy the code
  • An instance method reference to an existing object
Apple apple = new Apple();
Supplier<Integer> normal = () -> apple.getWeight();
Supplier<Integer> reference = apple::getWeight;
Copy the code
  • It can also be used for constructors
Supplier<Apple> normalSupplier = () -> new Apple();
Supplier<Apple> referenceSupplier = Apple::new;
Copy the code

conclusion

Above is the lambda expression in java8, there are some points that are not covered, but feel not particularly necessary, such as type inference how to infer, as well as lambda composition, throw exceptions, unboxing boxing also not covered. Then some things are not all out, you need to go to the idea into the source to watch.

The public,

If you are interested, you can follow the public account: CodeNode