preface

Only a bald head can be strong

I think it’s an Optional class. I think it’s an Optional class. I think it’s an Optional class.

  • As to whether she could understand it, it was certainly not. (How can a woman who has learned variables /for loops understand this?)

JDK 8 has an Optional class for you to use. This class can prevent NPE from happening as much as possible.

The text does its best to simply tell each point of knowledge, I hope we can have a harvest after reading

1. Foundation

We all know that the most important new feature in JDK 8 is Lambda expressions, which will allow us to simplify a lot of code writing. Here I simply with you to review ~

1.1Lambda simplified code example

Here are a few examples of how Lambda expressions can simplify writing code.

First let’s look at the creation thread:


public static void main(String[] args) {
    // Create threads with anonymous inner classes
    new Thread(new Runnable() {
        @Override
        public void run(a) {
            System.out.println("Public account: Java3y-- Reply 1 into group communication"); }});// Use Lambda to create a thread
    new Thread(() -> System.out.println("Public account: Java3y-- Reply 1 into group communication"));
}
Copy the code

Let’s look again at traversing the Map collection:



public static void main(String[] args) {
    Map<String, String> hashMap = new HashMap<>();
    hashMap.put("Public Account"."Java3y");
    hashMap.put("Communication group".Reply "1");

    // Iterate over the hashMap using enhanced for
    for (Map.Entry<String, String> entry : hashMap.entrySet()) {
        System.out.println(entry.getKey()+":"+entry.getValue());
    }

    // Use Lambda expressions to traverse the hashMap
    hashMap.forEach((s, s2) -> System.out.println(s + ":" + s2));
}
Copy the code

Delete an element from a List


public static void main(String[] args) {

    List<String> list = new ArrayList<>();
    list.add("Java3y");
    list.add("3y");
    list.add("Bald");
    list.add("Handsome boy");
    
    // Remove the "skinhead" element the traditional way
    ListIterator<String> iterator = list.listIterator();
    while (iterator.hasNext()) {
        if ("Bald".equals(iterator.next())) { iterator.remove(); }}// Delete the "skinhead" element in Lambda mode
    list.removeIf(s -> "Bald".equals(s));
    
    // Use Lambda to traverse the List collection
    list.forEach(s -> System.out.println(s));
}
Copy the code

As we can see from the above example, Lambda expressions can really help simplify our code.

1.1 Functional interface

Lambda expressions are actually built on functional interfaces. Let’s look at the interface of the code above:

Create a multithreaded Runnable interface:


@FunctionalInterface
public interface Runnable {
    public abstract void run(a);
}
Copy the code

Traverse the BiConsumer interface of the HashMap:


@FunctionalInterface
public interface BiConsumer<T.U> {
    void accept(T t, U u);
    default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
        Objects.requireNonNull(after);
        return(l, r) -> { accept(l, r); after.accept(l, r); }; }}Copy the code

Delete the Predicate interface from the List:


@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    default Predicate<T> negate(a) {
        return(t) -> ! test(t); }default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null== targetRef) ? Objects::isNull : object -> targetRef.equals(object); }}Copy the code

Features of functional interfaces: Identified by the @functionalInterface annotation, interfaces have one and only abstract method!

1.2Lambda brief explanation

Maybe when we first saw Lambda, we found the syntax of Lambda expressions a little weird, even a little confusing. Okay, so here’s 3y and I’ll draw it for you graphically:

Take the Runnable interface for example:

In addition, when using the IDE, we can prompt the syntax of Lambda expressions, which can help us quickly use Lambda expressions:

To be clear, we use Lambda expressions like this ()->{}, where we can look at the abstract method requirements of functional interfaces, or use IDE intelligent hints.

1.3 Generic review

Public Optional map(Function
mapper) this declaration, do you understand it?


/ / interface
@FunctionalInterface
public interface Function<T.R> {
    R apply(T t);
}
Copy the code

There is a principle behind the upper and lower limits of generics: PECS(Producer Extends Consumer Super)

  • Classes with subclass limits can be read from generics (that is, >(? Extend T)) ——–>Producer Extends
  • The ones with superclass qualification can be written from generics [i.e. >(? Super T)] ——–>Consumer super

Resolution: The argument passed is the generic T or its parent, and the return value is U or a subclass of it.

Please refer to:

  • Generics are as simple as that

Second, the Optional classes

Optional: Use JDK8’s Optional class to prevent NPE(null pointer exception) problems.

Here’s what the document says:

A container object which may or may not contain a non-null value.Additional methods that depend on the presence or absence of a contained value are provided

It is a container that holds non-null elements (or none) and provides a set of methods for determining whether objects in the container exist (and subsequent operations).

The Optional class method structure diagram:

2.1 Creating an Optional container

Let’s take a look at the Optional properties and how to create an Optional container:


	// Create an Optional container with no objects in it
    private static finalOptional<? > EMPTY =new Optional<>();

	// 2, represents the object in the container
    private final T value;

	// private constructor
    private Optional(a) {
        this.value = null;
    }

	// 4, get an Optional container, Optional does not hold objects
    public static<T> Optional<T> empty(a) {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

	// 5, private constructor (with arguments), the argument is the specific object to load, if the passed object is null, throw an exception
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

	If the object passed in is null, an exception is thrown
    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }


	// Create an Optional container and load the value into the Optional container.
	// If the value passed is null, throw an exception (Optional(T value) method is called)
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

	// Create the Optional container and load the object (value) into the Optional container.
	// The value passed in can be null. If null, an Optional object with no loaded object is returned
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
Copy the code

There are two ways to create an Optional container:

  • The ofNullable() method is called, and the object passed in can be NULL
  • When you call the of() method, the object passed in must not be null; otherwise, a NullPointerException is thrown

Here’s a quick look at how to use it:

I now have a User object that uses Lombok, so those of you who are interested should check it out: After two months of Java practice, keep working


import lombok.Data;
@Data
public class User {

    private Integer id;
    private String name;
    private Short age;
}

Copy the code

Testing:


public static void main(String[] args) {

    User user = new User();
    User user1 = null;

    // The object passed in cannot be considered null. If it is, an exception is thrown
    Optional<User> op1 = Optional.of(user1);

    // The object passed in can be null. If null, an Optional container with no loaded object is returned
    Optional<User> op2 = Optional.ofNullable(user);
}
Copy the code

2.2Optional Container Simple method


// Get the object in the container, throw an exception if null
public T get(a) {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

// Check whether the object in the container is null
public boolean isPresent(a) {
    returnvalue ! =null;
}

// Return if the object in the container exists. Otherwise return the parameter passed in
public T orElse(T other) {
    returnvalue ! =null ? value : other;
}

Copy the code

These three methods are commonly used by the Optional class and are among the simplest. (Because arguments are not functional interfaces)

Let’s continue with the usage:


public static void main(String[] args) {

        User user = new User();
        User user1 = null;

        Optional<User> op1 = Optional.ofNullable(user);
        System.out.println(op1.isPresent());
        System.out.println(op1.get());
        System.out.println(op1.orElse(user1));

    }
Copy the code

The result is obvious because our user is not null:

Let’s reverse the order:


public static void main(String[] args) {

    User user = new User();
    User user1 = null;

    Optional<User> op1 = Optional.ofNullable(user1);
    System.out.println(op1.isPresent());
    System.out.println(op1.orElse(user));
    System.out.println(op1.get());

}
Copy the code

2.3Optional Advanced container usage

Of course, it looks like the Optional class is the only thing we’ve seen so far, so it would be better if I wrote the code myself to determine null…

Let’s compare:

As you can see, it’s a little easier and cleaner to determine whether null is null manually.

So here comes our approach with a functional interface!

2.3.1 ifPresent method

Let’s start with ifPresent(Consumer
consumer) method



public void ifPresent(Consumer<? super T> consumer) {
    if(value ! =null)
        consumer.accept(value);
}

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

Copy the code

If the object in the container exists, the accept method is called, for example:


public static void main(String[] args) {

    User user = new User();
    user.setName("Java3y");
    test(user);
}

public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // If user exists, print the name of user
    optional.ifPresent((value) -> System.out.println(value.getName()));

    / / the old way
    if(user ! =null) { System.out.println(user.getName()); }}Copy the code

2.3.2orElseGet and orElseThrow methods

Direct look at the source code:


If the object exists, it is returned, otherwise it is used by the Supplier interface implementation to generate the default value
public T orElseGet(Supplier<? extends T> other) {
    returnvalue ! =null ? value : other.get();
}


@FunctionalInterface
public interface Supplier<T> {
    T get(a);
}


// If so, return. Otherwise, an exception created by the Supplier interface is thrown
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if(value ! =null) {
        return value;
    } else {
        throwexceptionSupplier.get(); }}Copy the code

Example:


public static void main(String[] args) {

    User user = new User();
    user.setName("Java3y");
    test(user);
}

public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // If there is a user, it returns directly, otherwise a new user object is created
    User user1 = optional.orElseGet(() -> new User());
    
    / / the old way
    if(user ! =null) {
        user = newUser(); }}Copy the code

Basically, it’s similar to orElse(), except that it can generate default values through the Supplier interface implementation.

2.3.3 filter method

Direct look at the source code:


// If the object in the container exists and meets the filtering criteria, return the Optional container containing the object, otherwise return an empty Optional container
public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if(! isPresent())return this;
    else
        return predicate.test(value) ? this : empty();
}


/ / interface
@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);
}
Copy the code

Return the Optional object and we can do the chain call!

Example:


public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // If the object in the container exists and meets the filtering criteria, return the Optional container containing the object, otherwise return an empty Optional container
    optional.filter((value) -> "Java3y".equals(value.getName()));
}

Copy the code

2.3.4 map method

Direct look at the source code:


// If the container object exists, call the mapping function to get the return value. Then create an Optional containing the value returned by the mapping, otherwise return empty Optional.
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if(! isPresent())return empty();
    else {
        returnOptional.ofNullable(mapper.apply(value)); }}/ / interface
@FunctionalInterface
public interface Function<T.R> {
    R apply(T t);
}
Copy the code

Example:


public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // If the container object exists, call the mapping function to get the return value. Then create an Optional containing the value returned by the mapping, otherwise return empty Optional.
    optional.map(user1 -> user1.getName()).orElse("Unknown");
}

// The last line of code corresponds to the original old way:

public String tradition(User user) {
    if(user ! =null) {
        return user.getName();
    }else{
        return "Unknown"; }}Copy the code

2.3.5 flatMap method

Direct look at the source code:


The flatMap method is similar to the map method except that the apply function returns a different value. What is the return value of the apply function of the map method? Extends U, and the apply function of the flatMap method must return Optional
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if(! isPresent())return empty();
    else {
        returnObjects.requireNonNull(mapper.apply(value)); }}Copy the code

2.3.6 summary

Feel the charm of Optional again


public static void main(String[] args) {
    User user = new User();
    user.setName("Java3y");
    System.out.println(test(user));
}

// Previous code v1
public static String test2(User user) {
    if(user ! =null) {
        String name = user.getName();
        if(name ! =null) {
            return name.toUpperCase();
        } else {
            return null; }}else {
        return null; }}// Previous code v2
public static String test3(User user) {
    if(user ! =null&& user.getName() ! =null) {
        return user.getName().toUpperCase();
    } else {
        return null; }}// The current code
public static String test(User user) {
    return Optional.ofNullable(user)
            .map(user1 -> user1.getName())
            .map(s -> s.toUpperCase()).orElse(null);
}
Copy the code

Optional:

Filter, map, or flatMap a function whose argument must not be null. Therefore, we can safely transform it through functions such as filter, map and flatMap, and finally extract the value through orElse series, GET, isPresent and ifPresent.

In fact, using the Optional class doesn’t simplify the code very much, just hides the NPE exception in various ways. Lambda expressions allow us to be a little more “elegant”.

Three, the last

There are many benefits to JDK updates (simplifying code, improving performance, etc.), so as a Java programmer, it is important to learn more about these new features. (There are new features in the JDK9 class.)

If you’re going to make comments like “wake up, programmers don’t have girlfriends” or “I piss yellow, let me do it”, I suggest you take a look at yourself, why all the other programmers have girlfriends and you don’t, are you not good enough? Would it be so hard to find one through the factory? You can make a new one of your own.

Of course, my girlfriend is real.

References:

  • Java 8 Optional class depth resolution: www.cnblogs.com/xingzc/p/57…
  • Java8 Optional:www.importnew.com/26066.html how to correctly use
  • www.zhihu.com/question/63…
  • Correct posture blog.csdn.net/hj7jay/arti jdk8 Java 】 【 Optional…

If you think my writing is good, know this:

  • Stick to the original technical public account: Java3y.
  • The table of contents navigation of this article (exquisite brain map + massive video resources) : github.com/ZhongFuChen…