13

最近、ランダムなアドホック テストでコードに異常なバグを発見しました。というわけで、テストケースを作りました。

これが私のテストケースです:

 SampleRequest request = new SampleRequest();
    request.setA(null);
    request.setB(null);
    assertEquals(null, request.getAOrB());

A と B は java.lang.Integer 型として定義されており、それらの値をリクエストに設定するためのダイレクト セッター メソッドがあります。

列挙も含まれます。プリミティブ整数値と、このコードで使用されるメソッドがあります。関連する部分をここに投稿します。

enum Swapper {
public int c;
Swapper findSwapperToUse(final int a) {
   for(Swapper swapper : values()) {
       if(swapper.c == a) {
          return swapper;
       }
   }
   return null;
}
}

さて、これが混乱している方法です。そのメソッドでテスト メソッドを呼び出すと、NPE が発生しますが、メソッドの最後の行で発生します。

    public class SampleRequest {
    private Integer A;
    private Integer B;

    public void setA(final Integer A) {
        this.A = A;
    }

    public void setB(final Integer B) {
        this.B = B;
    }


public Integer getAOrB() {
    return A != null ? Swapper.findSwapperToUse(A).c
         : B;
}
}

テストでは、A と B の両方が null に設定されます。したがって、A != null は false を返します。しかし、 : B 行の行番号で NullPointerException が発生します。

私の推測では、何らかの理由で最初の式 Swapper.findSwapperToUse(A).c が評価されているため、オートボクシングによって A.intValue() が呼び出され、null 値で NullPointerException が発生したと考えられます。デバッグを通じて、findSwapperToUse() が呼び出されていないことがわかっています。

ただし、この質問によると、これは発生しないはずです: Java 3 項 (即時の場合) 評価

選択されていないオペランド式は、条件式の特定の評価では評価されません。

null (B) を返しても NullPointerException は発生しません。ここで null の結果を返してもまったく問題ありません。

一体何が起こっているのですか?

編集:私はこれを避けるためにコードを変更したことを追加するのを忘れていました.ifステートメントをまっすぐに使用してください.

public Integer getAOrB() {
    if(A != null) {
        return Swapper.findSwapperToUse(A).c;
    }
    return B;
}
4

2 に答える 2

22

問題は、コンパイラが式全体の型を推測するという事実によって引き起こされていると思います

A != null ? Swapper.findSwapperToUse(A).c : B

intタイプからのようにSwapper.c、したがって、ボックス化解除変換を に適用しようとしますB

以下は、JLS §15.25からの関連する抜粋です。

  • それ以外の場合、2 番目と 3 番目のオペランドが数値型に変換可能な型 (§5.1.8) を持っている場合は、いくつかのケースがあります。
    • ...
    • それ以外の場合、2 進数値昇格 (§5.6.2) がオペランドの型に適用され、条件式の型は 2 番目と 3 番目のオペランドの昇格された型になります。バイナリ数値プロモーションでは、ボックス化解除の変換 (§5.1.8)と値セットの変換 (§5.1.13) が実行されることに注意してください。

次のキャストを追加することで、これを防ぐことができます。

A != null ? (Integer) Swapper.findSwapperToUse(A).c : B
于 2011-02-07T16:41:18.993 に答える
0

あなたのfindSwapperToUseメソッドは null を返していますが、できませんnull.c

これを確認するために、コードを次のように変更します。

public Integer getAOrB() {
    if(A != null) {
        Swapper foundSwapper = Swapper.findSwapperToUse(A);
        return foundSwapper.c;
    }
    return B;
}
于 2011-02-07T16:29:57.607 に答える