2016-07-29 56 views
7

比方说,我有多个构造一类,其中之一是一个拷贝构造函数(复制对象):Java的空参数时链构造

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

有没有什么办法可以让检查sourcenull在复制构造函数中,并且如果它是?IllegalArgumentException?因为其他构造函数调用已将作为我构造函数中的第一个语句。

+0

为什么其他构造函数调用必须是复制构造函数中的第一条语句? – Janno

+2

因为这就是Java所需要的。 – kalsowerus

+5

@Janno:因为这就是Java的工作原理。在另一个陈述之后不能使用this(...)。 –

回答

12

你可以这样做:

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

我也乔恩斯基特同意,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); 
} 
+0

checkNotNull方法应返回类型'T'的值。 – Omkar

+0

@Omkar ups,谢谢 – Dici

7

是的,你可以使用一个辅助方法,如果需要的话,这将引发异常,并返回原来的价值行吟诗人rwise ...你可以在你的构造函数调用中调用它,因为你允许方法调用作为参数评估的一部分。

// 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是推荐的例外反正这里扔(有效的Java第二版为例),其现有的代码将会抛出。所以你很可能不要想对你现有的代码做任何改变。

如果你想为这样的检查的辅助方法,但很高兴它扔NullPointerException,我推荐使用番石榴和其Preconditions类,它有这个和其他有用的检查方法很多

另请注意,Java 1.7引入了java.util.Objects它有requireNonNull,所以你甚至不需要第三方库。

+1

'NullPointerException'是否是相对的路?我以前看过'IllegalArgumentException'就是这样的情况。 – kalsowerus

+0

@kalsowerus'java.util.Objects.requireNonNull'抛出'NullPointerException',所以没关系。查看我的答案,看看几个例子(在我编辑它之后) – Dici

+0

@kalsowerus NPE意味着当你应该使用对象的引用时,你使用了一个'null'值。 –

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

请注意,这意味着'width'和'height'不能是最终的,这往往是一个非常重要的缺点。 –

+0

此外,由于从子类 – Dici

+0

@Dici yup无法看到“私人”方法,所以“私人最终”是多余的,这是真的,删除了“最终”。 – Mureinik

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

他想通过调用基础构造函数来避免代码重复并抛出验证异常。此代码不符合这两个要求 – Dici

+0

好的,非常感谢。我很抱歉,但这是我在这里的第一个答案。 –

+0

不用担心:)。好的旅程堆栈溢出 – Dici

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。请注意,如果您将这与一个空对象一起使用,这将导致一个NPE,这可能进一步表明NPE没有问题。

+0

请注意,复制'方法可能会在继承的情况下有问题 - 所有的子类将*有*覆盖此,以避免意外的行为。 – Hulk