尝试/捕获构造函数 - 推荐的做法?

2022-09-01 19:12:17

我一直很好奇的事情

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

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

变体 1:

如果捕获方法/构造函数中的异常,请确保将某些内容传递回调用方。您可以放置一个字段,如果一切正常,则该字段设置为 true。这看起来像这样:isValid

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()isValid()

变体 4:

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

这遵循JaxB和JaxRS的工作方式,这与你的情况类似。

  1. 外部数据源 - 您有一个文件,它们具有 XML 或 JSON 格式的传入消息。
  2. 构建对象的代码 - 你有你的代码,他们有他们的代码库根据各种JSR中的规范工作。
  3. 验证与对象的生成无关。

调用代码:

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

}

答案 2

您应该考虑静态工厂模式。使所有参数构造函数私有。提供一个静态 FileDataValidator(args...) 方法。这将接受并验证所有参数。如果一切正常,它可以调用私有构造函数并返回新创建的对象。如果有任何操作失败,请引发 Exception 以通知调用方它提供了错误的值。

我还必须提到:catch (Exception e) { printSomeThing(e); }

是你可以用例外做的最致命的反模式。是的,您可以在命令行上读取一些错误值,然后?调用方(提供错误值的调用方)不会收到错误值的通知,程序执行将继续。