Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 构造函数中的空检查与服务方法中的空检查?_Java_Oop_Object_Soa - Fatal编程技术网

Java 构造函数中的空检查与服务方法中的空检查?

Java 构造函数中的空检查与服务方法中的空检查?,java,oop,object,soa,Java,Oop,Object,Soa,这是我们的代码审查中的一个主题,我想听听更多的意见 假设我正在编写一个服务,它允许我将一个简单的Person对象插入数据库 public class Person { private String name; .... } 我们有一个简单的VerifyNotNull方法抛出IllegalArgumentException 你会选择哪条路线?为什么。 备选案文1: 验证Person对象的构造函数中是否不为null public Person(String name) {

这是我们的代码审查中的一个主题,我想听听更多的意见

假设我正在编写一个服务,它允许我将一个简单的Person对象插入数据库

public class Person
{
   private String name;
   ....
}
我们有一个简单的VerifyNotNull方法抛出IllegalArgumentException

你会选择哪条路线?为什么。

备选案文1:

验证Person对象的构造函数中是否不为null

public Person(String name)
{
     VerifyNotNull(name);//throws illegal arg exception if name is null
     this.name = name;
}

备选案文2:

允许使用null构造Person,在addPerson调用时验证NOTNULL

public class PersonService
{
  public void addPerson(Person personToAdd)
  {
     VerifyNotNull(personToAdd.getName());//throws illegal arg exception
     //add code
  }
}
我不喜欢在构造函数中抛出异常的想法。对我来说,选项2感觉不错,但我不知道如何解释或证明它

在构造函数中抛出异常是否可以接受


谢谢你的帮助

第一种方法是更快地失败,这将增加更快地找到bug来源的可能性。这样想:如果你的错误日志开始告诉你,由于你试图添加有空名字的人,出现了许多错误,你会想知道这些人的空名字来自哪里,对吗?根据您的系统的结构,可能是在距离用户添加到服务的位置几英里远的地方创建了用户。因此,您不知道代码中的4000个位置中的哪一个正在创建没有名字的人

所以如果我必须选择的话,我会选择第一个


当然,这取决于你的商业模式。如果一个人在数据输入阶段创建一个空名字是完全合法的,并且直到你准备好保存这个人的信息,你才想确保它通过了验证,那么情况就不同了。在这种情况下,您甚至可能希望生成一个
ValidatedPerson
类,该类包装
Person
,但以类型安全的方式指示只有在有人完成验证过程时才能调用
addPerson
方法,因为创建一个
ValidationPerson
的唯一方法是通过一个特定的
validate
方法来检查这个人的名字。

我会在Ctor中抛出异常。主要原因是:

  • 它甚至不允许创建无效的Person对象
  • 您不需要在应用程序中使用Person对象的每个点检查Person对象是否有效
  • 异常被抛出到导致无效人员对象存在的代码附近(例如,当您创建对象时,它被正确调用,当谁知道谁已经处理了对象时,它在代码中被调用)
  • 代码会很快失败——这是一个很好的实践

如果您使用的是IntelliJ,那么还可以使用JetBrain的@NotNull和@Nullable注释,因此,如果您使用null参数调用Ctor,IDE也会向您发出警告。请参阅。

在构造函数中抛出异常是可以接受的。然而,经过多年的经验,我发现检查构造函数或方法中的空参数或变量并不是必需的,除非您有办法恢复问题。如果没有恢复计划,那么程序肯定会失败。为了获得最佳实践,在传递构造函数或方法之前,应确保给定给它们的参数不为null(如果null不可接受)。

您的选择不受列出的两个选项的限制

  • 完全可以保证对象验证而不从构造函数引发异常
例如,可以使用工厂方法来实现:

class Person {
    private final String name;
    private Person(String name) { // private constructor
        this.name = name;
    }
    public static Person newPerson(String name) { // factory method
        VerifyNotNull(name); // IAE not from c'tor, guaranteed check
        return new Person(name);
    }
 }
另一种方法是,如果希望避免使用静态方法,可以使用如下生成器:

class Person {
    private final String name;
    private Person(String name) { // private constructor
        this.name = name;
    }

    /**
     * Usage: Person p = new Person.Builder(name).build();
     */
    public static class Builder {
        private final String name;
        public Builder(String name) {
            this.name = name;
        }
        public Person build() {
            VerifyNotNull(name); // IAE not from c'tor, guaranteed check
            return new Person(name);
        }
    }
}

两种不同的方法

第一种方法是快速失效——也就是说,您会尽快发现存在问题,错误会准确地显示空值是如何出现的(堆栈跟踪)。如果其他条件都相同,那就更好了


然而,只有当你确信一个人永远不需要名字时,这种方法才有效。您是否可能需要创建一个“占位符”人员,该人员暂时存在以提供某些功能,但实际上不需要姓名?如果是这样,那么您需要使用第二种方法。一般来说,占位符对象是一个坏主意,因此如果可以,请使用第一个占位符对象。但最终只有您知道您的应用程序。

名称不能为null的规则是业务逻辑,因此属于Person实体。因此,构造函数选项是两者中较好的。但是,您可能希望使用工厂方法(Evans):


我认为最好在服务方法内部抛出异常


原因是验证检查通常取决于特定应用程序的特定业务需求;服务层是大多数特定于应用程序的业务逻辑所在的地方(注意:有人反对这一点;另请参见:“贫血的域模型”)。如果在Person类中添加约束,则该类的可重用性/可移植性会降低,因为您可能希望在其他地方使用该类,该类允许在特定构造函数中使用null name属性。

我也不喜欢从初始值设定项引发异常——然而,我更希望使用该类,而不是带有“无效”(不可变)状态。选项#2的一个主要问题/区别是它可能永远不会通过
addPerson
:因此,空名称的问题只与PersonService有关。+1如果不能创建有效对象,我看不出有任何理由不在构造函数中抛出异常。而且它肯定是一个更好的选择周围有无效对象。因此,我们已将一个简单的
new Person(name)
转换为
new Person.Builder(name).build()
,其名称为..具体是什么?从中引发异常有什么问题
public class Person
{ 
    public Person()
    {
       //Nothing much here.
    }

    public static Person Create(String name)
    {
        VerifyNotNull(name);//throws illegal arg exception if name is null
        Person person = new Person();
        person.name = name;
        return person;
    }

    ...
}