Java 在构造函数中尝试/捕获-推荐做法?

Java 在构造函数中尝试/捕获-推荐做法?,java,oop,exception,try-catch,ooad,Java,Oop,Exception,Try Catch,Ooad,这是我一直好奇的事情 public class FileDataValidator { private String[] lineData; public FileDataValidator(String[] lineData){ this.lineData = lineData; removeLeadingAndTrailingQuotes(); try { validateName(); validateAge();

这是我一直好奇的事情

public class FileDataValidator {

private String[] lineData;

public FileDataValidator(String[] lineData){

    this.lineData = lineData;
    removeLeadingAndTrailingQuotes();

    try
    {
        validateName();
        validateAge();
        validateTown();
    }
    catch(InvalidFormatException e)
    {
        e.printStackTrace();
    }

}

//validation methods below all throwing InvalidFormatException
不建议在构造函数中包含try/catch块吗?
我知道我可以让构造函数将异常返回给调用方。像我在构造函数中所做的那样,你们更喜欢调用什么方法?在调用类中,您希望创建FileDataValidator的实例并调用该实例上的方法吗?只是有兴趣听到一些反馈

在您显示的代码中,验证问题不会与创建此对象实例的代码通信。这可能不是一件好事

变体1:

如果在方法/构造函数中捕获异常,请确保将某些内容传递回调用方。您可以将一个字段
isValid
设置为true(如果所有操作都有效)。看起来是这样的:

private boolean isValid = false;

public FileDataValidator(String[] lineData){

    this.lineData = lineData;
    removeLeadingAndTrailingQuotes();

    try
    {
        validateName();
        validateAge();
        validateTown();
        isValid = true;
    }
    catch(InvalidFormatException e)
    {
        isValid = false;
    }
}

public boolean isValid() {
    return isValid;
}
变体2:

或者,您可以让异常或其他异常传播到调用方。我已将其显示为未检查的异常,但请根据您的异常处理原则执行任何工作:

public FileDataValidator(String[] lineData){

    this.lineData = lineData;
    removeLeadingAndTrailingQuotes();

    try
    {
        validateName();
        validateAge();
        validateTown();
    }
    catch(InvalidFormatException e)
    {
        throw new com.myco.myapp.errors.InvalidDataException(e.getMessage());
    }

}
变体3:

我想提到的第三种方法的代码如下。在调用代码中,您必须调用构造函数,然后调用将起作用或不起作用的
build()
函数

String[] lineData = readLineData();
FileDataValidator onePerson = new FileDataValidator();
try {
    onePerson.build(lineData);
} catch (InvalidDataException e) {
    // What to do it its bad?
}
以下是课程代码:

public FileDataValidator() {
    // maybe you need some code in here, maybe not
}

public void build(String[] lineData){

    this.lineData = lineData;
    removeLeadingAndTrailingQuotes();

    try
    {
        validateName();
        validateAge();
        validateTown();
    }
    catch(InvalidFormatException e)
    {
        throw new com.myco.myapp.errors.InvalidDataException(e.getMessage());
    }

}
当然,
build()

变体4:

我想提到的第四种方法是我最喜欢的。它有这样的代码。在调用代码中,您必须调用构造函数,然后调用将起作用或不起作用的
build()
函数

String[] lineData = readLineData();
FileDataValidator onePerson = new FileDataValidator();
try {
    onePerson.build(lineData);
} catch (InvalidDataException e) {
    // What to do it its bad?
}
这种方式遵循JaxB和JAXR的工作方式,这与您的情况类似

  • 外部数据源—您有一个文件,它们有XML或JSON格式的传入消息
  • 构建对象的代码——您有自己的代码,它们的代码库根据各种JSR中的规范工作
  • 验证与对象的构建无关
  • 呼叫代码:

    String[] lineData = readLineData();
    Person onePerson = new Person();
    FileDataUtilities util = new FileDataUtilities();
    try {
        util.build(onePerson, lineData);
        util.validate(onePerson);
    } catch (InvalidDataException e) {
        // What to do it its bad?
    }
    
    以下是数据所在的类代码:

    public class Person {
        private Name name;
        private Age age;
        private Town town;
    ... lots more stuff here ...
    }
    
    以及用于构建和验证的实用程序代码:

    public FileDataValidator() {
        // maybe you need some code in here, maybe not
    }
    
    public void build(Person person, String[] lineData){
    
        this.lineData = lineData;
        removeLeadingAndTrailingQuotes();
        setNameFromData(person);
        setAgeFromData(person);
        setTownFromData(person);
    }
    
    public boolean validate(Person person) {
    
        try
        {
            validateName(person);
            validateAge(person);
            validateTown(person);
            return true;
        }
        catch(InvalidFormatException e)
        {
            throw new com.myco.myapp.errors.InvalidDataException(e.getMessage());
        }
    
    }
    

    我倾向于使用知道如何处理异常的代码来处理异常。在本例中,我假设创建FileDataValidator的代码位知道如果文件数据无效会发生什么,并且应该在那里处理异常(我主张传播给调用方)


    在讨论最佳实践时,我感觉到了类名称FileDataValidator。如果您正在创建的对象存储文件数据,那么我将称之为FileData—可能使用验证方法?如果您只想验证文件数据,那么静态方法就足够了。

    < P>您应该考虑静态工厂模式。将所有参数都设为私有构造函数。提供静态FileDataValidator(args…)方法。这将接受并验证所有参数。如果一切正常,它可以调用私有构造函数并返回新创建的对象。如果任何操作失败,抛出异常以通知调用方它提供了错误的值

    我还必须提到: 捕获(例外e){ 印刷品(e); }


    是对异常所能做的最致命的反模式。是的,您可以在命令行上读取一些错误值,然后?调用方(提供坏值的调用方)没有收到坏值的通知,程序将继续执行。

    更多关注的是,对于API,
    printStackTrace
    如何处理。当然,您应该让代码的用户遇到异常,以便他们可以对此做些什么?这就是异常的用途。如果所有三个
    validatexx
    调用都有效,为什么不将
    validatexx
    操作更改为返回布尔值,然后将名为
    valid
    的变量设置为。然后用
    isValid
    方法公开var out,在这里做一些可能有帮助的事情;也就是说,实例化一个您将多次调用的方法,传递数据以进行验证,然后让该方法执行异常抛出。您的第一种类型已损坏(构造函数中的方法?),第二种类型只是冗余练习。@GrantThomas我很想听到更多。我认为在构造函数中调用方法是没有问题的,如果这些方法有用的话。也许你可以解释一下。OP必须决定什么是有用的。第二,你是说
    抓回
    是多余的吗?@LeeMeador感谢你花这么多时间写出了几个想法!他们提供了许多值得思考的东西。我想我会选择变体3。从构造函数中移出验证调用并将异常传播给调用方就能够重用单个对象而言更为友好,调用类更适合于知道如果传递了无效数据会发生什么。@LeeMeador我还认为您的第一个示例被破坏了。实际上,您正在从构造函数中调用方法,这在语法上是正常的,但您也在构造函数中声明了一个方法
    isValid()
    。这是一个大括号问题。@Timmos修正了!谢谢你,谢谢你的建议。我非常喜欢在我的代码中实现模式,这是我一定会玩的东西。也谢谢你的反模式建议!老实说,我只是把它放在那里用于开发目的,直到我解决了最初的问题!