あなたは本当に三目演算子を使うことができますか?


前に書く:
三目演算子は、コードでよく使用されます.a= (b==null?0:1); のような行のコードは、if-else,の代わりに、コードをさわやかに読みやすくすることができます.しかし、三目演算子にも一定の言語規範がある.運用が不適切な場合、思いがけない問題を引き起こす.この間出会った(三目演算子の使用による問題は、実は三目演算子と自動分解ボックスが同時に使用されているためです(自動分解ボックスは私が自発的に使用しているわけではありませんが).
一、三項演算子
条件式b?x:yについては、まず条件bを計算し、判断する.bの値がtrueであれば、xの値を計算し、演算結果はxの値である.そうでなければ、yの値を計算し、演算結果はyの値とする.1つの条件式はxもyも計算しない.条件演算子は右結合、すなわち右から左へグループ化して計算されます.例えば、a?b:c?d:eはaを押しますか.b:(c?d:e)実行.
二、自動梱包と自動解体
基本データ型の自動梱包(autoboxing)、開梱(unboxing)はJ 2 SE 5.0より提供される機能です.一般にクラスのオブジェクトインスタンスを作成する場合、私たちはこのようにします:Class a = new Class(parameters);私たちがIntegerオブジェクトを作成すると、Integer i = 100;(注意:int i = 100;とは違います)実際に、上記のコードを実行すると、システムは私たちのために実行します:Integer i = Integer.valueOf(100);ここでは、この原理がどのように実現されるか(いつ箱を取り外すか、いつ箱を入れるか)はともかく、一般的なデータ型と対象タイプの違いも省略します.私たちが自分で書いたコードが箱を入れる規範に合致すると、コンパイラが自動的に箱を分解してくれると理解できます.では、プログラマーに制御されない自動分解箱に何か問題があるのではないでしょうか.
三、問題の回顧
まず、あなたの既存の経験を通じて、次のコードを見てみましょう.もしあなたが得た結果が後文分析の結果と一致したら(そして原理を知っています)、本文を無視してください.一致しなければ、私と一緒に探求してください.
Map map =  new HashMap();
Boolean b = (map!=null ? map.get("test") : false);

以上のコードは、私たちが気づかないうちによく書く可能性のあるコードの一種です(多くの場合、三目演算子を愛用しています).もちろん、このコードには問題があります.このコードを実行すると、NPEに報告されます.
Exception in thread "main" java.lang.NullPointerException

まず、空のポインタが報告されている以上、nullのオブジェクトを呼び出すいくつかの方法があるに違いない.この短い2行のコードの中で、map.get("test")を呼び出す方法は1つしかないように見えますが、mapは事前に初期化されており、Nullではありません.では、どこに空のポインタがあるのか知っています.次に、このコードを逆コンパイルします.私たちが書いたコードがコンパイラで処理されてからどうなったか見てみましょう.
逆コンパイル後のコードは次のとおりです.
HashMap hashmap = new HashMap();
Boolean boolean1 = Boolean.valueOf(hashmap == null ? false : ((Boolean)hashmap.get("test")).booleanValue());

この逆コンパイルされたコードを見た後、分析を経て、問題がどこにあるかを知ることができます.((Boolean)hashmap.get("test")).booleanValue()の実行プロセスおよび結果は次のとおりです.
hashmap.get(“test”)->null;
(Boolean)null->null;
null.booleanValue()->エラーを報告
はい、問題はやっと位置づけられました.では、この問題をどのように解決するか、なぜこのような問題が発生したのかを見てみましょう.
四、原理分析
逆コンパイル後のコードを見ることにより,問題を正確に特定し,解析後,NPEの原因は三目演算子と自動解体による空ポインタ異常であるべきであると結論した.
では、このコードはなぜ自動的に箱を分解するのでしょうか.これは実は三目演算子の文法規範です.jls-15.25を参照してください.要約は次のとおりです.
If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.
If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.
If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.
簡単に言えば、2番目、3番目のオペランドがそれぞれ基本タイプとオブジェクトである場合、そのオブジェクトはボックスを外して基本タイプとして操作されます.
したがって、結果として、3番目の演算子が使用され、2番目のオペランドと3番目のオペランドはそれぞれ基本タイプとオブジェクトである.したがって、オブジェクトはnullであるため、解体中にnullが呼び出される.booleanValue()の時にNPEに報告しました.
五、問題解決
コードがこのように書かれている場合は、エラーは発生しません.
Map<String,Boolean> map =  new HashMap<String, Boolean>();
Boolean b = (map!=null ? map.get("test") : Boolean.FALSE);

つまり、3番目の演算子の2番目の3番目のビットのオペランドがオブジェクトタイプであることを保証します.
これは三目演算子と関係があります.