Java 验证构造函数和setter中的字段是否被认为是错误的冗余代码?

Java 验证构造函数和setter中的字段是否被认为是错误的冗余代码?,java,coding-style,getter-setter,Java,Coding Style,Getter Setter,我有以下课程: public class Project { private int id; private String name; public Project(int id, String name) { if(name == null ){ throw new NullPointerException("Name can't be null"); } if(id == 0 ){

我有以下课程:

public class Project {

    private int id;
    private String name;  

    public Project(int id, String name) {
        if(name == null ){
            throw new NullPointerException("Name can't be null");
        }

        if(id == 0 ){
            throw new IllegalArgumentException("id can't be zero");
        }

            this.name = name;
            this.id = id;

    }

    private Project(){}

    public int getId() {
        return id;
    }

    public void setId(int id) { 
        if(id == 0 ){
            throw new IllegalArgumentException("id can't be zero");
        }
        this.id = id;
    }

    public String getName()
        return name;
    }

    public void setName(String name) {
        if(name == null ){
            throw new NullPointerException("Name can't be null");
        }
        this.name = name;
    }

}
如果您注意到setName和setId与构造函数共享其字段的相同验证。这是否是将来可能导致问题的冗余代码(例如,如果有人编辑setter以允许id为0并阻止-1,但没有更改构造函数)。我应该使用私有方法进行检查,并在构造函数和setter之间共享它吗?如果有很多字段,这似乎太多了


注意:这就是为什么我没有在构造函数中使用setter

我建议您将每个字段定义一个方法为
isValid()
,然后在setter和构造函数中调用相同的方法。

我会说是的。相反,只需从构造函数中调用setter:

public Project(int id, String name, Date creationDate, int fps, List<String> frames) {
    setName(name);
    setId(id);
    // other stuff with creationDate, fps and frames?
}
公共项目(int-id、字符串名称、创建日期、int-fps、列表帧){
集合名(名称);
setId(id);
//其他关于creationDate、fps和帧的东西?
}

另外,您不应该在
getName
中检查null
name
——在
setName
中进行检查。否则,bug将很难追踪——您希望在无效名称出现时立即捕获它,而不是在使用时捕获它(可能要晚得多)。

如果使
Project
不可变,它将消除冗余代码。但现在,我认为在构造函数和mutator方法中显式抛出异常是可以的


我不会在构造函数中调用mutator方法,原因有很多,包括。此外,我将删除访问者方法中的验证代码…这是不必要的。

以下是修订后的代码:

public class Project {

    private int id;
    private String name;  

    public Project(int id, String name, Date creationDate, int fps, List<String> frames) {

        checkId(id);
            checkName(name);
            //Insted of lines above you can call setters too.

            this.name = name;
            this.id = id;

    }

    private Project(){}

    public int getId() {
        return id;
    }

    public void setId(int id) { 
        checkId(id);
        this.id = id;
    }

    public String getName()
        return name;
    }

    public void setName(String name) {
            checkName(name);
        this.name = name;
    }

    private void checkId(int id){
       if(id == 0 ){
            throw new IllegalArgumentException("id can't be zero");
        }
    }

    private void checkName(String name){
            if(name == null ){
            throw new NullPointerException("Name can't be null");
        }
    }

}
公共类项目{
私有int-id;
私有字符串名称;
公共项目(int-id、字符串名称、创建日期、int-fps、列表框架){
支票id(id);
支票名称(姓名);
//除了上面的行,你也可以调用setter。
this.name=名称;
this.id=id;
}
私有项目(){}
公共int getId(){
返回id;
}
public void setId(int id){
支票id(id);
this.id=id;
}
公共字符串getName()
返回名称;
}
公共void集合名(字符串名){
支票名称(姓名);
this.name=名称;
}
私有无效检查id(内部id){
如果(id==0){
抛出新的IllegalArgumentException(“id不能为零”);
}
}
私有void checkName(字符串名称){
if(name==null){
抛出新的NullPointerException(“名称不能为null”);
}
}
}

如果您担心,请在CTOR中使用setter。或者(如果无法从构造函数调用setter),将验证逻辑传递给共享,私有方法。getter中的
private
构造函数和验证是怎么回事?@Captain Giraffe:这就是为什么我不使用setter@Captain Giraffe:所以如果有人重写setter而不添加验证(setter不是最终的),那么项目子类对象将无效。IMHO,这是一个糟糕的建议……除非您将mutator方法
设置为final
。因为如果有人覆盖
setName
setId
,这可能是灾难。不建议在同一个classGood catch中调用构造函数中的非私有或非final方法来同时调用这两个方法;如果使用这种方法,您应该使mutator方法(或整个类)
final
。当然,如果您使用类似于
isValid(String)
checkName(String)
的方法,同样的条件也适用。虽然是解决方案,但它仍然不能解决OPs问题。这是一种权衡,取决于开发人员的要求。取决于他们维护代码的方式。但是您认为isValid如何同时适用于id和name。