The default method of Java 8 provider

Posted by techcone on Wed, 11 Dec 2019 18:04:23 +0100

Java 8 API provides many new functional interfaces to make the work more convenient. Some interfaces are from Google Guava library. Even if you are familiar with these interfaces, it is necessary to see how they are extended to lambda.

I. Optional interface

1. Various problems caused by null

1) it is the source of error: NullPointException is the most typical exception in Java program development;
2) it will make your code inflate: it is to make your code full of deeply nested null checks, and the readability of the code is extremely poor.
3) it is meaningless in itself. null itself has no meaning. In particular, it represents the modeling of missing variables in a wrong way in statically typed languages.
4) it destroys the philosophy of Java. Java has been trying to avoid making programmers aware of pointers, with the only exception: null pointers.
5) it is a hole in the Java type system: null does not belong to any type, which means that it can be given a value to a variable of any reference type. This can cause problems because when the variable is passed to another part of the system, you won't know what the original assignment of the null variable is.

2. Get to know Optional

**Optional is not a function but an interface. It's an auxiliary type to prevent NullPointerException exception. This is an important concept to be used in the next session. Now let's see what this interface can do
Optional is defined as a simple container whose value may or may not be null. Before Java 8, a function should return a non empty object but occasionally it may return null. In Java 8, it is not recommended to return null but optional. * *

3. Use map

**Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName);
You can think of an Optional object as a special set of data that contains at most one element. If Optional contains a value, the function passes the value as a parameter to map and converts the value. If Optional is empty, do nothing. * *

3. Use flatMap

There is such abnormal Code: person.getCar().getInsurance().getName();
Non empty judgment must be very sad. Use flatmap to solve it easily: person. Flatmap (person:: getcar). Flatmap (car:: getinsurance). Map (Insurance:: getname). Orelse ("unknown");

4. Dereference Optional object

We decided to use the orElse method to read the value of this variable. In this way, you can also define a default value. When encountering an empty Optional variable, the default value will be the return value of the method call. The Optional class provides several methods to read the variable values in the Optional instance.
get() is the simplest and most insecure of these methods. If the variable exists, it directly returns the encapsulated variable value, otherwise a NoSuchElementException exception is thrown.
orElse(T other) allows you to provide a default value when the Optional object does not contain a value.
Orelseget (Supplier <? Extends T > other) is the delayed call version of orElse method. The Supplier method only calls when the Optional object does not contain a value.
orElseThrow (supplier <? Extensions x > exceptionsupplier) and get methods are very similar. They will throw an exception when the Optional object is empty, but you can customize the type of exception you want to throw with orElseThrow.
Ifpresent (consumer <? Super T >) allows you to execute a method passed in as a parameter when the variable value exists, otherwise no operation will be performed.

5. Methods of Optional class

Method describe
empty Return an optional instance
filter If the value exists and satisfies the provided predicate, an optional object containing the value is returned; otherwise, an empty optional object is returned
faltMap If the value exists, the supplied mapping function call is executed on the value, returning a value of type optional. Otherwise, an empty optional object is returned
get If the value exists, it is returned with optional encapsulation, otherwise a NoSunchElementException exception is thrown
ifPresent If the value exists, a method call using the value is executed, otherwise nothing is done
isPresent Returns true if the value exists, false otherwise
map If the value exists, the supplied mapping function call is performed on the value
map Returns the optional encapsulation of the specified value. If the value is null, a NullPointerException exception will be thrown
ofNullable Encapsulate the specified value with optional and return it. If the return is null, an empty optional object will be returned
ofElse If there is a value, return it, otherwise return a default value
ofElseGet If there is a value, return it; otherwise, return a value generated by the specified supplier interface
ofElseThrow Returns a value, if any, otherwise returns an exception generated by the specified supplier interface
import java.util.Optional;

public class Test {
 
    public static void main(String[] args) {
        
        Optional<String> optional = Optional.of("hello world");

        optional.isPresent();           // true
        optional.get();                 // "hello world"
        optional.orElse("fall back");    // "hello world"

        System.out.println("optional.isPresent() :" + optional.isPresent()); 
        System.out.println("optional.get() :" + optional.get()); 
        System.out.println("optional.orElse('fall back') :" + optional.orElse("fall back")); 
        
        optional.ifPresent((s) -> System.out.println(s.charAt(0)));     // "h"
    }
}

II. Predict interface

The Predicate interface has only one parameter and returns a boolean type. This interface contains several default methods to combine Predicate into other complex logic (such as and, or, non):

import java.util.function.Predicate;

public class Test {
 
    public static void main(String[] args) {
        
        Predicate<String> predicate = (s) -> s.length() > 0;

        predicate.test("foo");              // true
        predicate.negate().test("foo");     // false

        System.out.println("predicate.test('foo') :" + predicate.test("foo")); 
        System.out.println("predicate.negate().test('foo') :" + predicate.negate().test("foo")); 
    }
}

III. Function interface

The Function interface takes a parameter and returns a result, with some default methods (compose, andThen) that can be combined with other functions

import java.util.function.Function;

public class Test {
 
    public static void main(String[] args) {
        
        Function<String, Integer> toInteger = Integer::valueOf;
        Function<String, String> backToString = toInteger.andThen(String::valueOf);

        backToString.apply("123");     // "123"
        System.out.println("backToString.apply('123') :" + backToString.apply("123")); 
    }
}

IV. Supplier interface

The Supplier interface returns a value of any template. Unlike the Function interface, the interface does not have any parameters

$\ color{red} {sample code common class}$

import lombok.Data;

@Data
public class User implements Serializable{
    private static final long serialVersionUID = 1L;

    private String name;
    private String adress;
}

Supplier interface example

import java.util.function.Supplier;
import com.test.dao.User;

public class Test {
 
    public static void main(String[] args) {
        
        Supplier<User> personSupplier = User::new;
        personSupplier.get();   // new Person

        System.out.println("personSupplier.get() :" + personSupplier.get()); 
    }
}

V. Consumer interface

The Consumer interface represents the execution of an operation on a single parameter.

import java.util.function.Consumer;
import com.test.dao.User;

public class Test {
 
    public static void main(String[] args) {
        
        Consumer<User> greeter = (u) -> System.out.println("Hello, " + u.getName()); //"Hello, LiSi"
        greeter.accept(new User("LiSi", "ShenZhen"));
    }
}

Vi. Comparator interface

Comparator is a classic interface in old Java. Java 8 adds a variety of default methods on top of it:

import java.util.Comparator;
import com.test.dao.User;

public class Test {
 
    public static void main(String[] args) {
        
        Comparator<User> comparator = (p1, p2) -> p1.getName().compareTo(p2.getName());

        User p1 = new User("WangWu", "BeiJing");
        User p2 = new User("MaLiu", "ShangHai");

        comparator.compare(p1, p2);             // > 0 (comparator.compare(p1, p2) :10)
        comparator.reversed().compare(p1, p2);  // < 0 (comparator.reversed().compare(p1, p2) :-10)
        
        System.out.println("comparator.compare(p1, p2) :" + comparator.compare(p1, p2)); 
        System.out.println("comparator.reversed().compare(p1, p2) :" + comparator.reversed().compare(p1, p2)); 
    }
}

Vi. Stream interface

java.util.Stream represents the sequence of operations that can be applied to a group of elements at a time. Stream operations can be divided into intermediate operations or final operations. The final operation returns a specific type of calculation result, while the intermediate operation returns the stream itself, so you can string multiple operations in turn. Stream creation needs to specify a data source, such as the subclass of java.util.Collection, List or Set, which is not supported by Map. Stream operations can be performed serially or in parallel.

$\ color{red} {you can create a stream through Collection.stream() or Collection.parallelStream(). The details are described in 2. Stream API}$

VII. Filter

Filtering uses a predicate interface to filter and retain only qualified elements. This operation is an intermediate operation, so we can apply other Stream operations (such as forEach) to the filtered results. forEach needs a function to execute the filtered elements in turn. forEach is a final operation, so we cannot perform other Stream operations after forEach.

import java.util.ArrayList;
import java.util.List;


public class Test {
 
    public static void main(String[] args) {
        List<String> stringCollection = new ArrayList<>();
        stringCollection.add("ddd2");
        stringCollection.add("aaa2");
        stringCollection.add("bbb1");
        stringCollection.add("aaa1");
        stringCollection.add("bbb3");
        stringCollection.add("ccc");
        stringCollection.add("bbb2");
        stringCollection.add("ddd1");
        
        stringCollection
        .stream()
        .filter((s) -> s.startsWith("a"))
        .forEach(System.out::println); // "aaa2", "aaa1"

        System.out.println("stringCollection :" + stringCollection); 
}

VIII. Sort

Sorting is an intermediate operation, which returns the sorted Stream. If you do not specify a custom Comparator, the default sort will be used.

import java.util.ArrayList;
import java.util.List;


public class Test {
 
    public static void main(String[] args) {
        List<String> stringCollection = new ArrayList<>();
        stringCollection.add("ddd2");
        stringCollection.add("aaa2");
        stringCollection.add("bbb1");
        stringCollection.add("aaa1");
        stringCollection.add("bbb3");
        stringCollection.add("ccc");
        stringCollection.add("bbb2");
        stringCollection.add("ddd1");
        
        stringCollection
        .stream()
        .sorted()
        .filter((s) -> s.startsWith("a"))
        .forEach(System.out::println);// "aaa1", "aaa2"

//It should be noted that sorting only creates a Stream after sorting without affecting the original data source. After sorting, the original data stringCollection will not be modified.
        System.out.println("stringCollection :" + stringCollection); //[ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1]
    }
}

IX. Map mapping

The intermediate operation map will convert the elements to other objects according to the specified Function interface. The following example shows the conversion of strings to uppercase strings. You can also convert objects to other types through map. The Stream type returned by map is determined by the return value of the Function passed in by map.

import java.util.ArrayList;
import java.util.List;

public class Test {
 
    public static void main(String[] args) {
        List<String> stringCollection = new ArrayList<>();
        stringCollection.add("ddd2");
        stringCollection.add("aaa2");
        stringCollection.add("bbb1");
        stringCollection.add("aaa1");
        stringCollection.add("bbb3");
        stringCollection.add("ccc");
        stringCollection.add("bbb2");
        stringCollection.add("ddd1");
        
        stringCollection
        .stream()
        .map(String::toUpperCase)
        .sorted((a, b) -> b.compareTo(a))
        .forEach(System.out::println); //"DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"
        System.out.println("stringCollection :" + stringCollection); //[ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1]
    }
}

Match

Stream provides a variety of matching operations, allowing you to detect whether the specified Predicate matches the entire stream. All matching operations are final operations and return a value of type boolean.

import java.util.ArrayList;
import java.util.List;

public class Test {
 
    public static void main(String[] args) {
        List<String> stringCollection = new ArrayList<>();
        stringCollection.add("ddd2");
        stringCollection.add("aaa2");
        stringCollection.add("bbb1");
        stringCollection.add("aaa1");
        stringCollection.add("bbb3");
        stringCollection.add("ccc");
        stringCollection.add("bbb2");
        stringCollection.add("ddd1");
        
        boolean anyStartsWithA = 
            stringCollection
                  .stream()
                  .anyMatch((s) -> s.startsWith("a"));

        System.out.println(anyStartsWithA);      // true

        boolean allStartsWithA = 
            stringCollection
                  .stream()
                  .allMatch((s) -> s.startsWith("a"));

        System.out.println(allStartsWithA);      // false

        boolean noneStartsWithZ = 
            stringCollection
                  .stream()
                  .noneMatch((s) -> s.startsWith("z"));

        System.out.println(noneStartsWithZ);      // true

        System.out.println("stringCollection :" + stringCollection); //[ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1]
}

Xi. Count

Count is a final operation that returns the number of elements in the Stream and the return value type is long.

import java.util.ArrayList;
import java.util.List;

public class Test {
 
    public static void main(String[] args) {
        List<String> stringCollection = new ArrayList<>();
        stringCollection.add("ddd2");
        stringCollection.add("aaa2");
        stringCollection.add("bbb1");
        stringCollection.add("aaa1");
        stringCollection.add("bbb3");
        stringCollection.add("ccc");
        stringCollection.add("bbb2");
        stringCollection.add("ddd1");
        
        long startsWithB = 
                stringCollection
                    .stream()
                    .filter((s) -> s.startsWith("b"))
                    .count();

        System.out.println(startsWithB);    // 3

        System.out.println("stringCollection :" + stringCollection); // [ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1]
    }
}

12. Reduce protocol

This is a final operation. It allows multiple elements in a stream to be specified as one element through a specified function. The result after the specification is expressed through the Optional interface:

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class Test {
 
    public static void main(String[] args) {
        List<String> stringCollection = new ArrayList<>();
        stringCollection.add("ddd2");
        stringCollection.add("aaa2");
        stringCollection.add("bbb1");
        stringCollection.add("aaa1");
        stringCollection.add("bbb3");
        stringCollection.add("ccc");
        stringCollection.add("bbb2");
        stringCollection.add("ddd1");
        
        Optional<String> reduced =
                stringCollection
                    .stream()
                    .sorted()
                    .reduce((s1, s2) -> s1 + "#" + s2);

            reduced.ifPresent(System.out::println); //aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2

        System.out.println("stringCollection :" + stringCollection); // [ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1]
    }
}

XIII. Parallel Streams

As mentioned earlier, there are two kinds of streams: serial Stream and parallel Stream. The operations on serial Stream are completed successively in one thread, while parallel Stream is executed simultaneously on multiple threads.
How long does it take to calculate the serial sort

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class Test {
 
    public static void main(String[] args) {
        int max = 1000000;
        List<String> values = new ArrayList<>(max);
        for (int i = 0; i < max; i++) {
            UUID uuid = UUID.randomUUID();
            values.add(uuid.toString());
        }

        long t0 = System.nanoTime();

        long count = values.stream().sorted().count();
        System.out.println(count);

        long t1 = System.nanoTime();

        long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
        System.out.println(String.format("sequential sort took: %d ms", millis));
        // Sequential sort tool: 658 MS is executed several times, about 600 ms
    }
}

How long does it take to calculate the serial sort

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class Test {
 
    public static void main(String[] args) {
        int max = 1000000;
        List<String> values = new ArrayList<>(max);
        for (int i = 0; i < max; i++) {
            UUID uuid = UUID.randomUUID();
            values.add(uuid.toString());
        }
        
        
        long t0 = System.nanoTime();

        long count = values.parallelStream().sorted().count();
        System.out.println(count);

        long t1 = System.nanoTime();

        long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
        System.out.println(String.format("parallel sort took: %d ms", millis));
        // Parallel sort tool: 379 MS executes several times, about 300 ms
        
    }
}

The only change that needs to be made is to change stream() to parallel stream(), which is twice as fast as possible

Author:Soul Hau Xuan Welcome to the public address.

I reserve all rights and interests. Please indicate the source of reprint.
Welcome friends with stories and ideas to share with me, which can be sent to e-mail: lwqforit@163.com

Topics: Java Google Lambda Session