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

链接构造函数时的Java空参数,java,constructor,copy-constructor,Java,Constructor,Copy Constructor,假设我有一个具有多个构造函数的类,其中一个是复制构造函数(用于复制对象): 有没有办法检查复制构造函数中的source是否为null,如果是,则抛出IllegalArgumentException?因为另一个构造函数调用将作为我的构造函数中的第一个语句。您可以这样做: public Rectangle(Rectangle source) { this(checkNotNull(source, "Source cannot be null").width, source.height);

假设我有一个具有多个构造函数的类,其中一个是复制构造函数(用于复制对象):

有没有办法检查复制构造函数中的
source
是否为
null
,如果是,则抛出
IllegalArgumentException
?因为另一个构造函数调用作为我的构造函数中的第一个语句。

您可以这样做:

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;
}
如果生成错误消息的成本很高,您可以提供
供应商
,以仅在实际需要时支付构建消息的成本:

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

是的,您可以使用助手方法,该方法将在必要时引发异常,否则将返回原始值。。。您可以在构造函数调用中调用它,因为在参数求值中允许方法调用

// In a helper class
public static <T> T checkNotNull(T value) {
    if (value == null) {
        throw new IllegalArgumentException();
    }
    return value;
}
然而。。。我相信不管怎样,
NullPointerException
都是建议在这里抛出的异常(例如,在有效的Java第二版中),您现有的代码已经抛出了。因此,您很可能不想对现有代码进行任何更改

如果您想要一个用于此类检查的助手方法,但很高兴它抛出
NullPointerException
,我建议您使用Guava及其类,该类包含此方法和许多其他有用的检查方法


还请注意,Java 1.7引入了
requirennull
,因此您甚至不需要第三方库。

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

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;
    }
}
你可以这样做

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;
   }
}

如果您真的想抛出一个
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);
}


我更喜欢后者,因为它不需要担心矩形可能为空。请注意,如果将其与空对象一起使用,这将导致NPE,这可能进一步表明NPE没有问题。

为什么另一个构造函数调用必须是复制构造函数中的第一条语句?因为这是Java想要的。@Janno:因为Java就是这样工作的。您不能在另一个语句之后使用
this(…)
。当传递
null
时,我会将其保留为NPE。请注意,这意味着
宽度
高度
不能是最终值,这通常是一个非常重要的缺点。此外,
private final
是多余的,因为无法从subclasses@Dici是的,没错,删除了
final
@JonSkeet关于禁止成员成为final的技巧的有趣点。谢谢
NullPointerException
真的是一条路吗?我原以为以前见过要抛出的
IllegalArgumentException
就是这种情况。@kalsowerus
java.util.Objects.requirennoull
抛出一个
NullPointerException
,所以是的,这没问题。查看我的答案,看几个例子(在我编辑之后)@kalsowerus NPE意味着你在应该使用对象引用时使用了
null
值。@kalsowerus:NullPointerException是Josh Bloch推荐的,也是Google的样式指南使用的。这是我关于这些事情的主要真相来源:)@Dici:Ooh,我没有看到
对象。requirennoull
。他希望通过调用基本构造函数并抛出验证异常来避免代码重复。这段代码不满足这两个要求。好的,非常感谢。很抱歉,这是我在这里的第一个答案。不用担心:)。堆栈溢出的良好历程请注意,
copy
-方法在继承的情况下可能会有问题-所有子类都必须重写此方法以避免意外行为。checkNotNull方法应返回类型为“T”的值。
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;
   }
}
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);
}