Java8を使用するための正しい姿勢(オプション)

黄舟
リリース: 2017-01-18 15:24:46
オリジナル
1397 人が閲覧しました

Java プログラミング言語

java は、クロスプラットフォームのアプリケーション ソフトウェアを作成できるオブジェクト指向プログラミング言語です。これは、1995 年 5 月に Sun Microsystems によって開始された Java プログラミング言語および Java プラットフォームです (つまり、JavaEE (j2ee)、一般名)。 JavaME(j2me)、JavaSE(j2se))。


Java 8 にはいくつかの非常に便利な API が追加されていることはわかっていますが、その 1 つはオプションです。少し詳しく調べなければ、NullPointException 問題をエレガントに解決できるだろうと軽く考えて、コードを開始します。このように書くと

Optional<User> user = ……
if (user.isPresent()) {
return user.getOrders();
} else {
return Collections.emptyList();
}
ログイン後にコピー

そして、私たちの考え方は依然として同じところにあると言わなければなりませんが、これは本質的には User インスタンスの単なるラッパーであると考えます

User user = …..
if (user != null) {
return user.getOrders();
} else {
return Collections.emptyList();
}
ログイン後にコピー

これが私たちが話そうとしていることです。 Java 8 Optional タイプの正しい姿勢を使用してください。

リオオリンピック中、ニュースでは五つ星の赤旗に問題があると繰り返し取り上げられていましたが、私はそれができませんでした。どう考えても問題はありませんが、中央の小さな星を崇拝する姿勢は間違っていることがわかりました。つまり、Java 8 で Optional に切り替える場合、以前に null を扱ったときと同じ考え方を継承することはできません。Java 8 Optional を使用するための新しい正しい姿勢をマスターする必要があります。率直に言って、次のような方法で Optional を使用しているときは、自分自身でチェックを開始する必要があります

isPresent() メソッドを呼び出すとき

get() メソッドを呼び出すとき

Optional 型がクラスとして使用されているとき/instance 属性

Optional 型がメソッドのパラメータとして使用される場合

isPresent() は obj != null と何の違いもありませんが、isPresent() を使用せずに get() を呼び出すと、私たちの生活は依然として衝撃的になります。 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() 将会抛出一个异常)
ログイン後にコピー

IntelliJ IDEA では、属性またはメソッドのパラメーターとして Optional 型を使用することは強く推奨されません

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 类型不可被序列化, 用作字段类型会出问题的)
ログイン後にコピー

したがって、Optional では、実際に信頼できるのは、isPresent() と get() 以外の他のメソッドである必要があります:

public Optional map(Function マッパー)

public T orElse(T other )

public T orElseGet(Supplier other)

public void ifPresent(Consumer Consumer)

public Optional predicate public flatMap(Function ; マッパー)

public T orElseThrow(SupplierExceptionSupplier) throws

まず最初に、3 つの構造について触れなければなりません。 Optional のメソッド: Optional.of(obj)、Optional.ofNullable(obj)、およびクリア Optional.empty ()

Optional.of(obj): 受信した obj が null 値であってはいけないことが必要です。そうでない場合は、ロールに入る前に NullPointerException

Optional.ofNullable(obj): Optional インスタンスを構築するためのスマートで寛容な方法が必要です。null を渡すと、Optional.empty() が返されます。は null ではないので、Optional.of(obj) を呼び出します。

つまり、Optional を使用するだけでよいということですか? .ofNullable(obj) は一度だけ使用でき、次の方法で Optional インスタンスを構築するだけで十分です。は変更されず、2 番目の変更に適応しますか? それは必ずしも当てはまりません。そうでない場合、なぜ Optional.of(obj) がそれほど公開される必要があるのでしょうか?

私の個人的な意見は次のとおりです: 1. Optional.of(obj) に渡される obj パラメータを null にすることはできません。たとえば、それが新しく作成されたオブジェクト (Optional.of(new User(...))) である場合、またはオブジェクトが非-null 定数 2. obj が null ではないことを主張したい場合、つまり、obj が null の場合は、null ポインタ例外を非表示にするのではなく、すぐに NullPointException 例外を報告して変更したい場合は、決定的である必要があります。 Optional.of(obj) を使用して、Optional に隠れる機会を予測できない null 値に利用させずに、Optional インスタンスを構築します。

ここで、既存の Optional インスタンスの使用を開始します。オプションの ユーザー。if(user.isPresent()) { ... } else { ... }

存在する場合は返されます。存在しない場合は、デフォルト値

return user.orElse(null);  //而不是 return user.isPresent() ? user.get() : null;
return user.orElse(UNKNOWN_USER);
ログイン後にコピー

が存在する場合は返され、そうでない場合は関数によって生成されます

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)!


関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート