2016-07-29 25 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