Home  >  Article  >  Java  >  Correct posture for using Java8 Optional

Correct posture for using Java8 Optional

黄舟
黄舟Original
2017-01-18 15:24:461328browse

Java Programming Language

Java is an object-oriented programming language that can write cross-platform application software. It is a Java programming language and Java platform launched by Sun Microsystems in May 1995. (That is, the general name of JavaEE(j2ee), JavaME(j2me), JavaSE(j2se)).


We know that Java 8 has added some very useful APIs, one of which is Optional. If you don’t explore it a little bit, you just lightly think that it can elegantly solve NullPointException. problem, so the code started to be written like this

Optional<User> user = ……
if (user.isPresent()) {
return user.getOrders();
} else {
return Collections.emptyList();
}

So we have to say that our thinking is still at the same place, but we instinctively think that it is just a wrapper for the User instance, which is different from what we wrote before

User user = …..
if (user != null) {
return user.getOrders();
} else {
return Collections.emptyList();
}

There is essentially no difference. This is the correct posture for using Java 8 Optional types that we are going to talk about.

During the Rio Olympics, the news repeatedly mentioned that there was a problem with the five-star red flag, but I couldn't see anything wrong no matter how I looked at it, but later I realized that the posture of the little star worshiping the center was wrong. Therefore, we must not take things for granted that we are accustomed to, and we will not feel anything wrong at all. In other words, when When we switch to Java 8 Optional, we cannot inherit the way we used to treat null in the past. We should master the new and correct posture of using Java 8 Optional correctly.

To put it bluntly, when When we are still using Optional in the following ways, we have to start checking ourselves

When calling the isPresent() method

When calling the get() method

Optional type When used as a class/instance attribute

Optional type when used as a method parameter

isPresent() and obj != null There is no difference, our lives are still shocking at every step. Without isPresent( ) to pave the way for get() calls that will receive warnings in IntelliJ IDEA

Reports calls to java.util.Optional.get() without first checking with a isPresent() 
call if a value is available. If the Optional does not contain a value, get() will throw an exception. 
(调用 Optional.get() 前不事先用 isPresent() 检查值是否可用. 假如 Optional 不包含一个值, get() 将会抛出一个异常)

Using Optional types as attributes or method parameters is strongly not recommended in IntelliJ IDEA

Reports any uses of java.util.Optional<T>, java.util.OptionalDouble, java.util.OptionalInt, 
java.util.OptionalLong or com.google.common.base.Optional as the type for a field or a parameter. Optional was designed
 to provide a limited mechanism for library method return types where there needed to be a clear way to represent 
 “no result”. Using a field with type java.util.Optional is also problematic if the class needs to be Serializable, 
 which java.util.Optional is not. (使用任何像 Optional 的类型作为字段或方法参数都是不可取的. Optional 只设计为类库方法的,
  可明确表示可能无值情况下的返回类型. Optional 类型不可被序列化, 用作字段类型会出问题的)

So what we can really rely on in Optional should be other methods besides isPresent() and get():

public8f4f974c37a8b771235386e098482ce3 Optional8f4f974c37a8b771235386e098482ce3 map(Function6b6ab5be58a16060a43ff3e5755fd171 mapper)

public T orElse(T other)

public T orElseGet(Supplierd203bb1ae585225d4838a2b7e3d0503e other)

public void ifPresent(Consumer117c5a0bdb71ea9a9d0c2b99b03abe3e consumer)

public Optional8742468051c85b06f0a0af9e3e506b5c filter(Predicate117c5a0bdb71ea9a9d0c2b99b03abe3e predicate)

public8f4f974c37a8b771235386e098482ce3 Optional8f4f974c37a8b771235386e098482ce3 flatMap(Function mapper)

public e72eb6b20736125042e6673a1c58f23d T orElseThrow(Supplierb4690ad92a9d39463cecfa62549165e4 exceptionSupplier) throws .

First I have to mention the three construction methods of Optional: Optional.of(obj), Optional.ofNullable(obj) and explicit Optional.empty()

Optional.of (obj): It requires that the incoming obj cannot be null, otherwise you will get a NullPointerException before entering the role.

Optional.ofNullable(obj): It uses an intelligent method , a tolerant way to construct an Optional instance. All comers are welcome. If null is passed in, Optional.empty() will be obtained. If it is not null, Optional.of(obj) will be called.

Does that mean we only need to use Optional.ofNullable(obj) can be used once and for all, and it is enough to construct the Optional instance in a way that does not change and responds to the second change? That is not necessarily the case, otherwise, why should Optional.of(obj) be exposed like this? It can be private?

My own point of view is: 1. When we are very, very clear that the obj parameter to be passed to Optional.of(obj) cannot be null, for example, it is an object that has just been new (Optional.of(new User(. ..))), or when it is a non-null constant; 2. When we want to assert that obj is not null, that is, if we want to report a NullPointException exception immediately if obj is null, and modify it immediately, instead of hiding the null pointer exception. , we should decisively use Optional.of(obj) to construct Optional instances, without allowing any unpredictable null values ​​to take advantage of the opportunity to hide in Optional.

How to use an Optional now Existing Optional instances, assuming we have an instance Optional4c8e0c17c3bd7e0081bb17cc795e1984 user, here are a few common, if(user.isPresent()) { ... } else { ... } application methods that should be avoided.

If it exists, it will be returned. If it does not exist, it will provide a default value.

return user.orElse(null);  //而不是 return user.isPresent() ? user.get() : null;
return user.orElse(UNKNOWN_USER);

If it exists, it will be returned. If it does not exist, it will be generated by the function.

return user.orElseGet(() -> fetchAUserFromDatabase()); //而不要 return user.isPresent() ? user: fetchAUserFromDatabase();

存在才对它做点什么

user.ifPresent(System.out::println);

//而不要下边那样
if (user.isPresent()) {
  System.out.println(user.get());
}

map 函数隆重登场

当 user.isPresent() 为真, 获得它关联的 orders, 为假则返回一个空集合时, 我们用上面的 orElse, orElseGet 方法都乏力时, 那原本就是 map 函数的责任, 我们可以这样一行

return user.map(u -> u.getOrders()).orElse(Collections.emptyList())

//上面避免了我们类似 Java 8 之前的做法
if(user.isPresent()) {
  return user.get().getOrders();
} else {
  return Collections.emptyList();
}

map  是可能无限级联的, 比如再深一层, 获得用户名的大写形式

return user.map(u -> u.getUsername())
           .map(name -> name.toUpperCase())
           .orElse(null);

这要搁在以前, 每一级调用的展开都需要放一个 null 值的判断

User user = .....
if(user != null) {
  String name = user.getUsername();
  if(name != null) {
    return name.toUpperCase();
  } else {
    return null;
  }
} else {
  return null;
}

针对这方面 Groovy 提供了一种安全的属性/方法访问操作符 ?.

user?.getUsername()?.toUpperCase();

Swift 也有类似的语法, 只作用在  Optional 的类型上.

用了 isPresent() 处理 NullPointerException 不叫优雅, 有了  orElse, orElseGet 等, 特别是 map 方法才叫优雅.

其他几个, filter() 把不符合条件的值变为 empty(),  flatMap() 总是与 map() 方法成对的,  orElseThrow() 在有值时直接返回, 无值时抛出想要的异常.

一句话小结: 使用 Optional 时尽量不直接调用 Optional.get() 方法, Optional.isPresent() 更应该被视为一个私有方法, 应依赖于其他像 Optional.orElse(), Optional.orElseGet(), Optional.map() 等这样的方法.

最后, 最好的理解 Java 8 Optional 的方法莫过于看它的源代码 java.util.Optional, 阅读了源代码才能真真正正的让你解释起来最有底气, Optional 的方法中基本都是内部调用  isPresent() 判断, 真时处理值, 假时什么也不做.

以上就是使用 Java8 Optional 的正确姿势的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:10 lies about JavaNext article:10 lies about Java