web-dev-qa-db-ja.com

Javaで最初の非NULL値を取得する方法は?

SQLのCOALESCE関数に相当するJava同等物はありますか?つまり、いくつかの変数の最初の非ヌル値を返す方法はありますか?

例えば.

Double a = null;
Double b = 4.4;
Double c = null;

ab、およびcの最初のnull以外の値を返すステートメントをどうにかしたい-この場合、bを返す、または4.4。 (sqlメソッドのようなもの-COALESCE(a,b,c)を返します)。私はそれを次のように明示的に行うことができることを知っています:

return a != null ? a : (b != null ? b : c)

しかし、これを実現するための組み込みの受け入れられた機能があるのだろうかと思いました。

138
froadie

いいえ、ありません。

最も近いものは次のとおりです。

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 ...
}
102
les2
159
Andrzej Polis

チェックする変数が2つだけで、Guavaを使用している場合は、 MoreObjects.firstNonNull(T first、T second) を使用できます。

56
Dave

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
41

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);
}
24
Eric

この状況では、いくつかのプリプロセッサが必要です。なぜなら、最初の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 –(チェコ語で書かれていますが、コード例は誰でも理解できることを望みます)。

8
Franta

グアバでできること:

Optional.fromNullable(a).or(b);

abの両方がnullの場合、NPEはスローされません。

編集:私は間違っていた、それはNPEをスローしません。 MichalČizmaziaでコメントされている正しい方法は:

Optional.fromNullable(a).or(Optional.fromNullable(b)).orNull();
5
Jamol

完成度を高めるために、「いくつかの変数」のケースが実際に可能ですが、エレガントではありません。たとえば、変数op、およびqの場合:

Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )

op、および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() ) ) ;

さらに、関数宣言スタイルにも移行している場合、op、および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>を返します。

そして、coalesceeffectiveAge.get()になり、Supplier<Integer>に満足している場合は単にeffectiveAgeになります。

私見では、Java 8を使用すると、特に複雑なケースでは非常に自明で効率的であるため、このような構造のコードがますます増えます。

Lazy<T>を1回だけ呼び出すクラスSupplier<T>がありませんが、Optional<T>の定義の一貫性だけでなく、遅延もあります(つまり、Optional<T>-Optional<T>演算子、またはSupplier<Optional<T>>も)。

4
Mario Rossi

これを試すことができます:

public static <T> T coalesce(T... t) {
    return Stream.of(t).filter(Objects::nonNull).findFirst().orElse(null);
}

this responseに基づく

3
Lucas León

高価な方法の評価を避けたい場合は、サプライヤーを使用してはどうですか?

このような:

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);
}
1
Triqui

どうですか:

firstNonNull = FluentIterable.from(
    Lists.newArrayList( a, b, c, ... ) )
        .firstMatch( Predicates.notNull() )
            .or( someKnownNonNullDefault );

Java ArrayListは、nullエントリを便利に許可し、この式は、考慮されるオブジェクトの数に関係なく一貫しています。 (この形式では、考慮されるすべてのオブジェクトが同じタイプである必要があります。)

0
Lonnie