SQLのCOALESCE
関数に相当するJava同等物はありますか?つまり、いくつかの変数の最初の非ヌル値を返す方法はありますか?
例えば.
Double a = null;
Double b = 4.4;
Double c = null;
a
、b
、およびc
の最初のnull以外の値を返すステートメントをどうにかしたい-この場合、b
を返す、または4.4。 (sqlメソッドのようなもの-COALESCE(a,b,c)
を返します)。私はそれを次のように明示的に行うことができることを知っています:
return a != null ? a : (b != null ? b : c)
しかし、これを実現するための組み込みの受け入れられた機能があるのだろうかと思いました。
いいえ、ありません。
最も近いものは次のとおりです。
public static <T> T coalesce(T ...items) {
for(T i : items) if(i != null) return i;
return null;
}
効率的な理由から、次のように一般的なケースを処理できます。
public static <T> T coalesce(T a, T b) {
return a == null ? b : a;
}
public static <T> T coalesce(T a, T b, T c) {
return a != null ? a : (b != null ? b : c);
}
public static <T> T coalesce(T a, T b, T c, T d) {
return ...
}
Apache Commons Lang 3
ObjectUtils.firstNonNull(T...)
Java 8ストリーム
Stream.of(T...).filter(Objects::nonNull).findFirst().orElse(null)
チェックする変数が2つだけで、Guavaを使用している場合は、 MoreObjects.firstNonNull(T first、T second) を使用できます。
Testへの参照が2つだけで、Java 8を使用している場合は、使用できます
Object o = null;
Object p = "p";
Object r = Optional.ofNullable( o ).orElse( p );
System.out.println( r ); // p
Static Optionalをインポートする場合、式はそれほど悪くありません。
残念ながら、「いくつかの変数」のケースはOptional-methodでは不可能です。代わりに使用できます:
Object o = null;
Object p = null;
Object q = "p";
Optional<Object> r = Stream.of( o, p, q ).filter( Objects::nonNull ).findFirst();
System.out.println( r.orElse(null) ); // p
LES2の回答に続いて、オーバーロードされた関数を呼び出すことにより、効率的なバージョンでの繰り返しを排除できます。
public static <T> T coalesce(T a, T b) {
return a != null ? a : b;
}
public static <T> T coalesce(T a, T b, T c) {
return a != null ? a : coalesce(b,c);
}
public static <T> T coalesce(T a, T b, T c, T d) {
return a != null ? a : coalesce(b,c,d);
}
public static <T> T coalesce(T a, T b, T c, T d, T e) {
return a != null ? a : coalesce(b,c,d,e);
}
この状況では、いくつかのプリプロセッサが必要です。なぜなら、最初のnull以外の値を選択する関数(静的メソッド)を作成すると、すべてのアイテムが評価されるためです。一部の項目がメソッド呼び出しである場合(時間のかかるメソッド呼び出しである場合があります)は問題です。そして、このメソッドは、それらの前の項目がnullでなくても呼び出されます。
このような機能
public static <T> T coalesce(T ...items) …
使用する必要がありますが、バイトコードにコンパイルする前に、この「合体関数」の使用法を見つけ、次のような構造に置き換えるプリプロセッサが必要です。
a != null ? a : (b != null ? b : c)
2014-09-02の更新:
Java 8とLambdasのおかげで、Javaで真の融合を実現できる可能性があります。重要な機能を含む:特定の式は必要な場合にのみ評価されます。以前の式がnullでない場合、次の式は評価されません(メソッドは呼び出されず、計算またはディスク/ネットワーク操作は実行されません)。
私はそれについて記事を書きました Java 8:合体–hledámeneNULLovéhodnoty –(チェコ語で書かれていますが、コード例は誰でも理解できることを望みます)。
グアバでできること:
Optional.fromNullable(a).or(b);
a
とb
の両方がnull
の場合、NPEはスローされません。
編集:私は間違っていた、それはNPEをスローしません。 MichalČizmaziaでコメントされている正しい方法は:
Optional.fromNullable(a).or(Optional.fromNullable(b)).orNull();
完成度を高めるために、「いくつかの変数」のケースが実際に可能ですが、エレガントではありません。たとえば、変数o
、p
、およびq
の場合:
Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )
o
、p
、およびq
が変数ではなく、高価な、または望ましくない副作用を伴う式である場合に対応するorElseGet()
の使用に注意してください。
最も一般的な場合coalesce(e[1],e[2],e[3],...,e[N])
coalesce-expression(i) == e[i] when i = N
coalesce-expression(i) == Optional.ofNullable( e[i] ).orElseGet(()-> coalesce-expression(i+1) ) when i < N
これにより、式が過度に長くなる可能性があります。ただし、null
のない世界に移動しようとする場合、v[i]
は、おそらく単にString
とは対照的に、すでにOptional<String>
型です。この場合、
result= o.orElse(p.orElse(q.get())) ;
または式の場合:
result= o.orElseGet(()-> p.orElseGet(()-> q.get() ) ) ;
さらに、関数宣言スタイルにも移行している場合、o
、p
、およびq
は、次のようなタイプSupplier<String>
である必要があります。
Supplier<String> q= ()-> q-expr ;
Supplier<String> p= ()-> Optional.ofNullable(p-expr).orElseGet( q ) ;
Supplier<String> o= ()-> Optional.ofNullable(o-expr).orElseGet( p ) ;
そして、coalesce
全体が単純にo.get()
に減少します。
より具体的な例:
Supplier<Integer> hardcodedDefaultAge= ()-> 99 ;
Supplier<Integer> defaultAge= ()-> defaultAgeFromDatabase().orElseGet( hardcodedDefaultAge ) ;
Supplier<Integer> ageInStore= ()-> ageFromDatabase(memberId).orElseGet( defaultAge ) ;
Supplier<Integer> effectiveAge= ()-> ageFromInput().orElseGet( ageInStore ) ;
当然、defaultAgeFromDatabase()
、ageFromDatabase()
、およびageFromInput()
はすでにOptional<Integer>
を返します。
そして、coalesce
はeffectiveAge.get()
になり、Supplier<Integer>
に満足している場合は単にeffectiveAge
になります。
私見では、Java 8を使用すると、特に複雑なケースでは非常に自明で効率的であるため、このような構造のコードがますます増えます。
Lazy<T>
を1回だけ呼び出すクラスSupplier<T>
がありませんが、Optional<T>
の定義の一貫性だけでなく、遅延もあります(つまり、Optional<T>
-Optional<T>
演算子、またはSupplier<Optional<T>>
も)。
これを試すことができます:
public static <T> T coalesce(T... t) {
return Stream.of(t).filter(Objects::nonNull).findFirst().orElse(null);
}
this responseに基づく
高価な方法の評価を避けたい場合は、サプライヤーを使用してはどうですか?
このような:
public static <T> T coalesce(Supplier<T>... items) {
for (Supplier<T> item : items) {
T value = item.get();
if (value != null) {
return value;
}
return null;
}
そして、次のように使用します:
Double amount = coalesce(order::firstAmount, order::secondAmount, order::thirdAmount)
また、2、3、または4つの引数を使用して、オーバーロードされたメソッドを呼び出しに使用することもできます。
さらに、次のようなストリームを使用することもできます。
public static <T> T coalesce2(Supplier<T>... s) {
return Arrays.stream(s).map(Supplier::get).filter(Objects::nonNull).findFirst().orElse(null);
}
どうですか:
firstNonNull = FluentIterable.from(
Lists.newArrayList( a, b, c, ... ) )
.firstMatch( Predicates.notNull() )
.or( someKnownNonNullDefault );
Java ArrayListは、nullエントリを便利に許可し、この式は、考慮されるオブジェクトの数に関係なく一貫しています。 (この形式では、考慮されるすべてのオブジェクトが同じタイプである必要があります。)