CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第8章 その他の Java 8 機能を理解する : 問題 14 : requireNonNull(T, Supplier<String>) メソッド

問題

java.util.ObjectsrequireNonNull(T, Supplier<String>)メソッドは

  • 第1引数がnullかどうかをチェックし
  • nullのときは第2引数のラムダ式を評価して
  • それをエラーメッセージとするNullPointerExceptionをスローする

このメソッドによりもっと役立つエラーメッセージとなる方法を示せ。

疑問点

よりもっと役立つエラーメッセージとなる” の意味が分からない。

本文には、次のサンプルコードがあった。
■ 本文のサンプルコード

this.directions = Objects.requireNonNull(
    directions,
    () -> "directions for " + this.goal + " must not be null"
);

下のコードと比べれば、第2引数の文字列連結処理がnullのときしか実行されないというメリットはあるんだが…

this.directions = Objects.requireNonNull(
    directions,
    "directions for " + this.goal + " must not be null"
);

よりもっと役立つエラーメッセージ” って何だろう?

解答

本文に載っているコードは、あるクラスのコンストラクタの一部だろうと思う。
goal とか directions というメンバー変数から推測するに、このクラスは「迷路を歩き回る経路」を表わしているのだろう。

話を簡単にするために、経路を進む方向は東西南北の4つしかないとする。

■ 経路を進む方向

public enum Direction {
    North, East, South, West
}

requireNonNullを使わない経路クラス

public class Path {
    private Point2D start;           // 出発点
    private Direction[] directions;  // 経路を進む方向

    public Path(Point2D start, Direction[] directions) {
        this.start = start;
        this.directions = directions;
    }

    // ゴールを求める
    public Point2D getGoal() {
        if (directions == null) {
            return start;
        }
        Point2D goal = new Point2D(start.getX(), start.getY());
        for (Direction direction : directions) {
            switch (direction) {
            case North: goal = goal.add( 0.0, -1.0); break;
            case East:  goal = goal.add( 1.0,  0.0); break;
            case South: goal = goal.add( 0.0,  1.0); break;
            case West:  goal = goal.add(-1.0,  0.0); break;
            }
        }
        return goal;
    }
}

このコンストラクタにrequireNonNullメソッドを使ってnullチェックを行うと

requireNonNullを使ってnullチェック

public Path(Point2D start, Direction[] directions) {
    this.start = Objects.requireNonNull(start, "~");
    this.directions = Objects.requireNonNull(
        directions,
        () -> "directions for " + getGoal() + " must not be null"
    );
}

getGoal()メソッドは、directionsnullでないときはコストが掛かる。
NullPointerExceptionがスローされないときも律儀にゴールを計算するのは無駄である。