链接构造函数时的Java null参数

时间:2016-07-29 09:42:42

标签: java constructor copy-constructor

让我们说我有一个包含多个构造函数的类,其中一个是复制构造函数(复制对象):

public class Rectangle {

    int width, height;

    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public Rectangle(Rectangle source) {
        this(source.width, source.height);
    }
}

我有什么方法可以检查复制构造函数中source是否为null,如果是IllegalArgumentException则会抛出?{1}}因为其他构造函数调用成为构造函数中的第一个语句。

5 个答案:

答案 0 :(得分:13)

你可以这样做:

public Rectangle(Rectangle source) {
     this(checkNotNull(source, "Source cannot be null").width, source.height);
}

private static <T> T checkNotNull(T t, String msg) {
    if (t == null) throw new IllegalArgumentException(msg);
    return t;
}

我也同意Jon Skeet的观点,NullPointerException在这种情况下并不是一个坏的bevahiour。唯一的问题是,在获得NPE的情况下排长队时,可能有点难以确定哪个对象是null,这就是更具体的消息可能有用的原因。

如果您不打扰投掷java.util.Objects,也不能重新发明轮子并使用标准NullPointerException方法:

public Rectangle(Rectangle source) {
     this(Objects.requireNonNull(source, "Source cannot be null").width, source.height);
}

如果您的错误消息构建成本很高,则可以提供Supplier<String>代替,只有在实际需要时才支付构建消息的费用:

 public Rectangle(Rectangle source) {
     this(Objects.requireNonNull(source, () -> explainError(source)).width, source.height);
}

答案 1 :(得分:8)

是的,你可以使用一个帮助方法,如果有必要会抛出异常,否则返回原始值...你可以在构造函数调用中调用它,因为你允许方法调用作为参数的一部分评价。

// In a helper class
public static <T> T checkNotNull(T value) {
    if (value == null) {
        throw new IllegalArgumentException();
    }
    return value;
}

然后将其用作:

public Rectangle(Rectangle source) {
    this(Helper.checkNotNull(source).width, source.height);
}

但是......我认为NullPointerException是推荐的例外(例如,在Effective Java第2版中),你的现有代码已经抛出。因此,您很可能想要对现有代码进行任何更改。

如果你想要一个像这样的检查的辅助方法,但很高兴它抛出NullPointerException,我建议使用Guava及其Preconditions类,它有这个和一个很多其他有用的检查方法。

另请注意,Java 1.7引入了java.util.Objects requireNonNull,因此您甚至不需要第三方库。

答案 2 :(得分:3)

一个教科书技巧是将初始化从构造函数移到方法中。然后,您可以在它之前获得您想要的任何代码:

public class Rectangle {

    int width, height;

    public Rectangle(int width, int height) {
        init(width, height);
    }

    public Rectangle(Rectangle source) {
        if (source == null) {
            throw new IllegalArgumentException("source can't be null!");
        }
        init(source.width, source.height);
    }

    private void init(int width, int height) {
        this.width = width;
        this.height = height;
    }
}

答案 3 :(得分:2)

如果你确实想要抛出IllegalArgumentException,我认为最干净的解决方案是使用静态方法而不是构造函数:

public static Rectangle from(Rectangle source) {
    if (source == null) {
        throw new IllegalArgumentException("source can't be null!");
    }
    return new Rectangle(source.width, source.height);
}

或者您可以添加复制方法:

public Rectangle copy() {
    return new Rectangle(this.width, this.height);
}

我更喜欢后者,因为它不需要关注Rectangle可能为null。请注意,如果将此对象与null对象一起使用,则会导致NPE,这可能进一步表明NPE正常。

答案 4 :(得分:1)

你可以这样做

int width, height;

public Rectangle(int width, int height) {
    this.width = width;
    this.height = height;
}

public Rectangle(Rectangle source) {
   if(source != null) {
      width = source.width;
      height = source.height;
   }
}