如何验证复制构造函数的参数?

时间:2017-07-04 20:31:27

标签: java validation parameters null 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);
  } 
}

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

有没有办法可以检查copy-constructor中的source是否为null,如果是,则抛出IllegalArgumentException?因为其他构造函数调用必须是我的构造函数中的第一个语句。

5 个答案:

答案 0 :(得分:2)

您可以引入一个私有静态方法,通过null检查返回相关值以抛出IllegalArgumentException(在这种情况下是宽度,因为它是同一对象上的第一个参数)。

例如:

public class Rectangle {

    private int width, height;

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

    public Rectangle(Rectangle rectangle) {
        this(getWidth(rectangle), rectangle.height);
    }

    private static int getWidth(Rectangle rectangle) {
        if (rectangle == null) {
            throw new IllegalArgumentException("null value");
        }
        return rectangle.width;
    }

}

反思上述问题的评论,为什么不NullPointerException

这个问题:IllegalArgumentException or NullPointerException for a null parameter?有一些很好的讨论要点。但我倾向于同意“有效Java”的观点,NullPointerException应该优先考虑answer中提到的那个问题。

  

“可以说,所有错误的方法调用都归结为非法   参数或非法状态,但标准使用其他例外   对于某些非法论点和国家。如果来电者通过   在禁止空值的某些参数中为null,   约定规定抛出NullPointerException而不是   抛出:IllegalArgumentException“。

答案 1 :(得分:1)

你可以使用java.lang.Objects,但它会抛出NullPointerException(带有你提供的消息)而不是IllegalArgumentException:

    public class Rectangle {

    private int width, height;

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

    public Rectangle(Rectangle rectangle) {
        this(Objects.requiresNotNull(rectangle, "rectangle was null").getWidth(), getHeight(rectangle));
    }
    ...
    }

如果您愿意,也可以将宽度和高度设为最终。

答案 2 :(得分:0)

如果你打开复制构造函数的替代品,那么复制静态工厂 - 请参阅Josh Bloch的 Effective Java ,第2版,项目11,第61页 - 会为您带来更大的灵活性:

public final class Rectangle {

  private final int width
  private final int height;

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

  public static Rectangle newInstance(Rectangle source) {// <-- copy static factory
    if (source == null) {
      throw new IllegalArgumentException("null source");
    }

    return new Rectangle(source.width, source.height);
  }

}

可以说,抛出NullPointerException比投掷IllegalArgumentException更具惯用性。

答案 3 :(得分:0)

如果你的代码库中某处有这个方法:

IllegalArgumentException

您可以使用它从构造函数中抛出public class Rectangle { int width, height; public Rectangle(int width, int height) { this.width = width; this.height = height; } public Rectangle(Rectangle source) { this(getIfNotNull(source, s -> s.width), source.height); } }

IllegalArgumentException

免责声明:只需抛出一个NullPointerException就可以了所有这一点,这比NullPointerException更少惯用。一般来说,如果某个不可为空的参数为null,则抛出position: relative是一种好习惯。在尝试取消引用该参数时,您的原始代码已经这样做了。

答案 4 :(得分:0)

可能最简单的解决方法是不要让构造函数调用另一个构造函数。没有任何优势,除非您正在进行课堂作业,并告知您必须这样做:

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

public Rectangle(Rectangle rectangle) {
    if (rectangle == null) {
        throw new IllegalArgumentException(...);
    }
    this.width = rectangle.width;
    this.height = rectangle.height;
}

当然,您现在拥有重复的代码,但将其提取到两个构造函数使用的新私有方法中非常简单。

对于我而言,这似乎比发明一种将空检查机制成this(...)的方式更为直接,正如其他几个答案所做的那样。