web-dev-qa-db-ja.com

Java "?" nullをチェックするための演算子-それは何ですか?(Ternaryではありません!)

私はスラッシュドットの物語からリンクされた記事を読んでいて、このちょっとしたちょっとした話に出くわしました。

Javaの最新バージョンを使用してください。Javaは、無限のポインターテスト用の簡略構文を提供することにより、ヌルポインターのチェックを容易にします。各メソッド呼び出しに疑問符を追加するだけで、次のようなif-thenステートメントのネズミのネストを置き換えるヌルポインターのテストが自動的に含まれます。


    public String getPostcode(Person person) {
      String ans= null;
      if (person != null) {
        Name nm= person.getName();
        if (nm!= null) {
          ans= nm.getPostcode();
        }
      }
      return ans
    } 

これとともに:


public String getFirstName(Person person) {
      return person?.getName()?.getGivenName();
    } 

私はインターネットを精査しました(大丈夫、「Java疑問符」のバリエーションをグーグルで少なくとも15分費やしました)、何もありませんでした。だから、私の質問:これに関する公式文書はありますか? C#には同様の演算子( "??"演算子)があることがわかりましたが、使用している言語のドキュメントを取得したいと思います。前に見たことがない。

ありがとう!

編集:記事へのリンク: http://infoworld.com/d/developer-world/12-programming-mistakes-avoid-292

68
Erty Seidohl

元のアイデアはグルーヴィーから来ています。 Project Coinの一部としてJava 7に対して提案されました: https://wiki.openjdk.Java.net/display/Coin/2009+Proposals+TOC (エルビスおよびその他のNull-Safeオペレーター)、しかしまだ受け入れられていません。

関連するエルビス演算子?:は、x ?: yの短縮形としてx != null ? x : yを作成するために提案されました。これは、xが複雑な式である場合に特に便利です。

69
ataylor

この構文はJavaには存在せず、私が知っている今後のバージョンのいずれにも含まれる予定もありません。

53
ColinD

Java 7で提案がありましたが、拒否されました:

http://tech.puredanger.com/Java7/#null

16
PaulJWilliams

「?」の欠如を回避する1つの方法Java 8をtry-catchのオーバーヘッドなしで使用する(前述のようにNullPointerExceptionを非表示にすることもできます)を使用する)は、 Java-8-Streamスタイル。

public class Pipe<T> {
    private T object;

    private Pipe(T t) {
        object = t;
    }

    public static<T> Pipe<T> of(T t) {
        return new Pipe<>(t);
    }

    public <S> Pipe<S> after(Function<? super T, ? extends S> plumber) {
        return new Pipe<>(object == null ? null : plumber.apply(object));
    }

    public T get() {
        return object;
    }

    public T orElse(T other) {
        return object == null ? other : object;
    }
}

次に、指定された例は次のようになります。

public String getFirstName(Person person) {
    return Pipe.of(person).after(Person::getName).after(Name::getGivenName).get();
}

[編集]

さらに考えてみると、標準のJava 8クラスを使用してのみ、同じことを実際に達成できることがわかりました。

public String getFirstName(Person person) {
    return Optional.ofNullable(person).map(Person::getName).map(Name::getGivenName).orElse(null);
}

この場合、デフォルト値を選択することも可能です("<no first name>"nullの代わりにorElseのパラメーターとして渡すことにより。

15
Helder Pereira

参照: https://blogs.Oracle.com/darcy/project-coin:-the-final-five-or-so (具体的には「エルビスおよびその他のヌルセーフ演算子」)。

その結果、この機能はJava 7で考慮されましたが、含まれていませんでした。

7
Darron

実際には Groovyの安全な参照解除演算子 です。 pure Java(悲しい))で使用することはできません。そのため、投稿は単純に間違っています(または、Groovyが「Javaの最新バージョン」であると主張している場合は、少し誤解を招く可能性があります)。

6
Andrzej Doyle

Java 8 lambda。でほぼきれいな方法でこれを解決するutilメソッドを定義することが可能です。

これは H-MANs solution のバリエーションですが、NullPointerExceptionをキャッチする代わりに、複数の引数を持つオーバーロードメソッドを使用して複数のステップを処理します。

この解決策はちょっとクールだと思っていても、 Helder Pereira's 秒の方が好きだと思います。これはutilメソッドを必要としないからです。

void example() {
    Entry entry = new Entry();
    // This is the same as H-MANs solution 
    Person person = getNullsafe(entry, e -> e.getPerson());    
    // Get object in several steps
    String givenName = getNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.getGivenName());
    // Call void methods
    doNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.nameIt());        
}

/** Return result of call to f1 with o1 if it is non-null, otherwise return null. */
public static <R, T1> R getNullsafe(T1 o1, Function<T1, R> f1) {
    if (o1 != null) return f1.apply(o1);
    return null; 
}

public static <R, T0, T1> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, R> f2) {
    return getNullsafe(getNullsafe(o0, f1), f2);
}

public static <R, T0, T1, T2> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Function<T2, R> f3) {
    return getNullsafe(getNullsafe(o0, f1, f2), f3);
}


/** Call consumer f1 with o1 if it is non-null, otherwise do nothing. */
public static <T1> void doNullsafe(T1 o1, Consumer<T1> f1) {
    if (o1 != null) f1.accept(o1);
}

public static <T0, T1> void doNullsafe(T0 o0, Function<T0, T1> f1, Consumer<T1> f2) {
    doNullsafe(getNullsafe(o0, f1), f2);
}

public static <T0, T1, T2> void doNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Consumer<T2> f3) {
    doNullsafe(getNullsafe(o0, f1, f2), f3);
}


class Entry {
    Person getPerson() { return null; }
}

class Person {
    Name getName() { return null; }
}

class Name {
    void nameIt() {}
    String getGivenName() { return null; }
}
2
Lii

Javaにはexact構文はありませんが、JDK-8では、さまざまなメソッドを自由に使用できる Optional API があります。したがって、 null条件演算子 を使用したC#バージョン:

return person?.getName()?.getGivenName(); 

Java with Optional API で次のように記述できます。

 return Optional.ofNullable(person)
                .map(e -> e.getName())
                .map(e -> e.getGivenName())
                .orElse(null);

persongetName、またはgetGivenNameのいずれかがnullの場合、nullが返されます。

1
Aomine

これがうまくいくかどうかはわかりません。たとえば、人の参照がnullの場合、ランタイムはそれを何に置き換えますか?新しい人?この場合、Personには、この場合に予想されるデフォルトの初期化が必要です。 null参照例外を回避できますが、これらのタイプのセットアップを計画していなかった場合、予測できない動作が発生します。

?? C#の演算子は、「合体」演算子と最もよく呼ばれる場合があります。複数の式を連鎖させることができ、それはヌルではない最初の式を返します。残念ながら、Javaにはありません。最善の方法は、三項演算子を使用してnullチェックを実行し、チェーン内のメンバーがnullの場合は式全体の代替を評価することです:

return person == null ? "" 
    : person.getName() == null ? "" 
        : person.getName().getGivenName();

Try-catchを使用することもできます。

try
{
   return person.getName().getGivenName();
}
catch(NullReferenceException)
{
   return "";
}
1
KeithS

誰かが古いJavaバージョンの代替を探しているなら、私が書いたこれを試すことができます:

/**
 * Strong typed Lambda to return NULL or DEFAULT VALUES instead of runtime errors. 
 * if you override the defaultValue method, if the execution result was null it will be used in place
 * 
 * 
 * Sample:
 * 
 * It won't throw a NullPointerException but null.
 * <pre>
 * {@code
 *  new RuntimeExceptionHandlerLambda<String> () {
 *      @Override
 *      public String evaluate() {
 *          String x = null;
 *          return x.trim();
 *      }  
 *  }.get();
 * }
 * <pre>
 * 
 * 
 * @author Robson_Farias
 *
 */

public abstract class RuntimeExceptionHandlerLambda<T> {

    private T result;

    private RuntimeException exception;

    public abstract T evaluate();

    public RuntimeException getException() {
        return exception;
    }

    public boolean hasException() {
        return exception != null;
    }

    public T defaultValue() {
        return result;
    }

    public T get() {
        try {
            result = evaluate();
        } catch (RuntimeException runtimeException) {
            exception = runtimeException;
        }
        return result == null ? defaultValue() : result;
    }

}
0
irobson

Androidは、インストールされているOSが24以上でない限り、Lambda関数をサポートしないため、リフレクションを使用する必要があります。

// Example using doIt function with sample classes
public void Test() {
    testEntry(new Entry(null));
    testEntry(new Entry(new Person(new Name("Bob"))));
}

static void testEntry(Entry entry) {
    doIt(doIt(doIt(entry,  "getPerson"), "getName"), "getName");
}

// Helper to safely execute function 
public static <T,R> R doIt(T obj, String methodName) {
    try {
       if (obj != null) 
           return (R)obj.getClass().getDeclaredMethod(methodName).invoke(obj);
    } catch (Exception ignore) {
    }
    return null;
}
// Sample test classes
    static class Entry {
        Person person;
        Entry(Person person) { this.person = person; }
        Person getPerson() { return person; }
    }

    static class Person {
        Name name;
        Person(Name name) { this.name = name; }
        Name getName() { return name; }
    }

    static class Name {
        String name;
        Name(String name) { this.name = name; }
        String getName() {
            System.out.print(" Name:" + name + " ");
            return name;
        }
    }
}
0
LanDenLabs

そこに、Java 8:

public void someMethod() {
    String userName = nullIfAbsent(new Order(), t -> t.getAccount().getUser()
        .getName());
}

static <T, R> R nullIfAbsent(T t, Function<T, R> funct) {
    try {
        return funct.apply(t);
    } catch (NullPointerException e) {
        return null;
    }
}
0
H-MAN

指定したコードをテストすると、構文エラーが発生します。そのため、Javaではサポートされていません。 Groovyはそれをサポートしており、Java 7(ただし、含まれることはありません))向けに提案されました。

ただし、Java 8で提供されているOptionalを使用できます。これは、同様の行で何かを達成するのに役立つ場合があります。 https://docs.Oracle.com/javase/8/docs/ api/Java/util/Optional.htmlhttp://www.Oracle.com/technetwork/articles/Java/java8-optional-2175753.html

オプション のサンプルコード

0
SK -