Detailed usage of Optional in Java 8 features

foreword

NPE (NullPointerException) has always been the most hated exception for Java programmers. The lengthy non-null check makes the code's readability and elegance greatly reduced. So in this article, the author will introduce in detail the feature introduced by Java 8 - the Optional class, and see how it avoids null pointer exceptions.

What are Optionals?

Optional is a container object that may or may not contain non-null values. isPresent() will return true if the value is present and get() will return the value. Additional methods are provided that depend on the presence or absence of the contained value, such as orElse() (returns a default value if the value is not present) and ifPresent() (executes a piece of code if the value is present). This is a value-based class; using identity-sensitive operations on Optional instances, including reference equality (==), identity hash codes, or synchronization, may have unpredictable results and should be avoided .

What problem does Optional solve?

Before Java 8, we performed object validation like this:

public String getCity(User user){
    
    
    if(user != null){
    
    
        Address address = user.getAddress();
        if(address != null){
    
    
            return address.getCity();
        }else{
    
    
            return "北京市";
        }
    }else{
    
    
        return "北京市";
    }
}

Java 8 way of writing:

public String getCity(User user){
    
    
    return Optional.ofNullable(user)
        .map(u -> u.getAddress())
        .map(address -> address.getCity())
        .orElse("北京市");

}

Detailed method

empty

describe

Returns an empty Optional instance.

source code
public static<T> Optional<T> empty() {
    
    
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}
usage
Optional<Object> empty = Optional.empty();

An empty Optional object is created. If the get() method is called at this time, NoSuchElementException will be thrown

Optional<Object> empty = Optional.empty();
System.out.println(empty.get());// 抛出 NoSuchElementException

of(T value)

describe

Create an Optional for a non-null value, and the incoming parameter cannot be null, otherwise a NullPointerException will be thrown.

source code
public static <T> Optional<T> of(T value) {
    
    
    return new Optional<>(value);
}
usage
Optional<String> userName = Optional.of("userName");

If null is passed in, a NullPointerException will be thrown

Optional<String> userName = Optional.of(null);// 抛出 NullPointerException

ofNullable(T value)

describe

Creates a nullable Optional, and returns the specified value described by the Optional if it is non-null, otherwise returns an empty Optional.

source code
public static <T> Optional<T> ofNullable(T value) {
    
    
	return value == null ? empty() : of(value);
}
usage
Optional<String> userName = Optional.ofNullable("userName");

get()

describe

If this value is included in this Optional, return the value, otherwise throw an exception: NoSuchElementException.

source code
public T get() {
    
    
    if (value == null) {
    
    
    	throw new NoSuchElementException("No value present");
    }
    return value;
}
usage
Optional<String> userName = Optional.ofNullable("userName");
System.out.println(userName.get());//输出 userName

isPresent()

describe

Returns true if a value exists, false otherwise.

source code
public boolean isPresent() {
    
    
	return value != null;
}
usage
Optional<String> userName = Optional.ofNullable("userName");
System.out.println(userName.isPresent());//输出 true
Optional<String> empty = Optional.ofNullable(null);
System.out.println(empty.isPresent());//输出 false

ifPresent(Consumer<? super T> consumer)

describe

Calls the consumer with the value if it exists, otherwise does nothing.

To understand the ifPresent method, you first need to understand the Consumer class. In short, the Consumer class contains one abstract method. This abstract method processes the passed in value, but does not return a value. Java8 supports passing parameters directly through lambda expressions without interfaces.
If the Optional instance has a value, the call to ifPresent() can accept an interface segment or a lambda expression.

source code
public void ifPresent(Consumer<? super T> consumer) {
    
    
	if (value != null)
		consumer.accept(value);
}
usage
Optional<String> userName = Optional.ofNullable("userName");
userName.ifPresent((value) -> System.out.println(value.length()));//输出 8
Optional<String> empty = Optional.ofNullable(null);
empty.ifPresent((value) -> System.out.println(value.length()));//无输出,此时Optional为空值,不执行操作

filter(Predicate<? super T> predicate)

describe

If the value exists and matches the given predicate, returns an Optional describing the value, otherwise returns an empty Optional.

source code
public Optional<T> filter(Predicate<? super T> predicate) {
    
    
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}
usage
Optional<String> userName = Optional.ofNullable("userName");
Optional<String> filterUserName1 = userName.filter((value) -> value.length() > 4);
System.out.println(filterUserName1.get());//输出 userName
Optional<String> filterUserName2 = userName.filter((value) -> value.length() < 4);
System.out.println(filterUserName2.get());//抛出 NoSuchElementException,因为此时没有找到匹配的值,返回一个空的Optional

map(Function<? super T, ? extends U> mapper)

describe

If there is a value, call the mapping function on it to get the return value. If the return value is not null, create an Optional containing the return value of the map as the return value of the map method, otherwise return an empty Optional.

source code
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    
    
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
    
    
        return Optional.ofNullable(mapper.apply(value));
    }
}
usage
Optional<String> userName = Optional.ofNullable("userName");
Optional<String> mapUserName = userName.map((value) -> value.toUpperCase(Locale.ROOT));
System.out.println(mapUserName.get());//输出 USERNAME 

flatMap(Function<? super T, Optional> mapper)

describe

If the value exists, return the value based on the mapping method included in Optional, otherwise return an empty Optional, this method is similar to map(Function), but the return value of the provided mapper must be Optional, if called, flatMap will not use additional Optional wraps it.

source code
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    
    
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
    
    
        return Objects.requireNonNull(mapper.apply(value));
    }
}
usage
Optional<String> userName = Optional.ofNullable("userName");
Optional<String> flatMapUserName = userName.flatMap((value) ->
                 	Optional.of(value.toUpperCase(Locale.ROOT)) //mapper的返回值必须为Optional
);
System.out.println(flatMapUserName.get());//输出 USERNAME

orElse(T other)

describe

If the value exists, return value, otherwise return other.

source code
public T orElse(T other) {
    
    
    return value != null ? value : other;
}
usage
Optional<String> userName = Optional.ofNullable("userName");
System.out.println(userName.orElse("mobile"));//输出 userName
Optional<Object> empty = Optional.empty();
System.out.println(empty.orElse("mobile"));//输出 mobile

orElseGet(Supplier<? extends T> other)

describe

If the value exists, return the value, otherwise trigger other and return the result of the other call. orElseGet is similar to the orElse method, the difference is the default value obtained. The orElse method takes the incoming string as the default value, and the orElseGet method can accept the implementation of the Supplier interface to generate the default value.

source code
public T orElseGet(Supplier<? extends T> other) {
    
    
    return value != null ? value : other.get();
}
usage
Optional<String> userName = Optional.ofNullable("userName");
System.out.println(userName.orElseGet(() -> "mobile"));//输出 userName
Optional<Object> empty = Optional.empty();
System.out.println(empty.orElseGet(() -> "mobile"));//输出 mobile

orElseThrow(Supplier<? extends X> exceptionSupplier)

describe

Returns the contained value if present, otherwise throws an exception inherited from Supplier

source code
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    
    
    if (value != null) {
    
    
        return value;
    } else {
    
    
        throw exceptionSupplier.get();
    }
}
usage
try {
    
    
    Optional<String> userName = Optional.ofNullable("userName");
    System.out.println(userName.orElseThrow(Exception::new));//输出 userName
} catch (Exception e) {
    
    
    e.printStackTrace();
}
try {
    
    
    Optional<Object> empty = Optional.empty();
    System.out.println(empty.orElseThrow(Exception::new));
} catch (Exception e) {
    
    
    e.printStackTrace(); //异常捕获
}

Summarize

The above is an introduction to the usage of each method of Optional. It is recommended that you use it proficiently, so that your code can become more elegant.

Guess you like

Origin blog.csdn.net/yupengfei112233/article/details/127664807