Java 在这种情况下,可以从构造函数抛出异常吗?

Java 在这种情况下,可以从构造函数抛出异常吗?,java,exception,constructor,Java,Exception,Constructor,在为学校项目开发课程(如学校课程)数据库系统时,我偶然发现了一个争论的问题 我有一门课叫“课程”。下面是类的构造函数(另一个是分配默认值的空白构造函数): public Course(String name, String code, char level, int academicYear) { serialNumber = nextSerialNumber++; if (name == null) { throw new NullPointerExc

在为学校项目开发课程(如学校课程)数据库系统时,我偶然发现了一个争论的问题

我有一门课叫“课程”。下面是类的构造函数(另一个是分配默认值的空白构造函数):

public Course(String name, String code, char level, int academicYear)
{
    serialNumber = nextSerialNumber++;
    if (name == null) 
    {
        throw new NullPointerException("Name can not be null.");
    }
    else
    {
        this.name = name;
    }  
    if (code == null)
    {
        throw new NullPointerException("Code can not be null.");
    }
    else
    {
        this.code = code;
    }
    if (indexOf(level, VALID_LEVEL) == -1)
    {
        throw new InvalidLevelException("Level must be one of " 
            + "characters defined in the public array in Course.");
    }
    else
    {
        this.level = level;
    }
    if (String.valueOf(academicYear).length() != NUMBER_OF_DIGITS_IN_YEAR)
    {
        throw new InvalidYearException("Year must be a four digit number!");
    }
    else
    {
        this.academicYear = academicYear;
    }
}
在哪里

是属于的子类的自定义异常

RuntimeException
我从该构造函数抛出异常,以指示是否出现了任何错误。例如,如果在读取数据文件时遇到坏数据,我可以拒绝它并将其写入日志(根据项目要求),只需将该构造函数放入try-catch块,然后捕获这些异常,然后在catch块内记录坏数据

在向我的老师展示了这段代码之后,他说从构造函数抛出异常是不合适的。然而,我读过许多鼓励这种做法的帖子

我的问题是:可以从上述构造函数抛出异常吗

如有信誉良好的资料来源(如官方文件或权威书籍),并附上答复,将不胜感激

非常感谢

可以从上述构造函数抛出异常吗

您的问题涉及异常处理的一个方面。另一个方面是准确描述问题。我将简要介绍这两个方面

代码失败时是否引发异常?

原因很简单。您希望用户确切地知道问题发生的位置,如果您将异常传播到所有地方,那么您将使代码用户更难破译问题所在。如果问题发生在对象的构造函数中,则您知道问题发生在该对象的创建过程中

这为用户提供了一个重要的线索,这就是您所能做的。您不知道用户将如何误用您的代码,因此您需要让他们尽可能容易地破译问题的根源

异常消息是否描述了问题?

使用适当类型的
异常
非常重要。如果他们提供了无效参数,则抛出一个
IllegalArgumentException
。如果它们提供了空值,则抛出一个
NullPointerException
异常
应尽可能有效地描述问题

第二部分是您附加的消息。我见过的次数:

Exception: Exception Occurred
高得令人沮丧。它一点帮助都没有,而且是一种非常懒惰的处理代码的方法。你需要澄清:

NullPointerException: Parameter X was null
用户立即知道他们传递给
X
的值是
null
。简单地说,确保消息专门描述了导致它的问题

额外阅读

  • 有关此主题的更多详细信息,请查看有关异常处理的最佳实践。这将有助于澄清您遇到的任何其他问题

我认为在构造函数中抛出异常没有任何错误。这意味着无法在有效状态下创建对象

就个人而言,您抛出了正确的异常,但如果可以使用Java异常,
invalidleveleexception
InvalidYearException
应替换为
IllegalArgumentException
,则不要使用自定义异常,而
NullPointerException
是参数为null的正确异常

我想改变的另一件事是风格:检查你的论点,然后做其他的事情

public Course(String name, String code, char level, int academicYear)
{
    if (name == null) {
        throw new NullPointerException("Name can not be null.");
    }
    if (code == null) {
        throw new NullPointerException("Code can not be null.");
    }

    if (indexOf(level, VALID_LEVEL) == -1) {
        throw new InvalidLevelException("Level must be one of " 
            + "characters defined in the public array in Course.");
    }

    if (String.valueOf(academicYear).length() != NUMBER_OF_DIGITS_IN_YEAR) {
        throw new InvalidYearException("Year must be a four digit number!");
    }

    serialNumber = nextSerialNumber++;
    this.code = code;
    this.academicYear = academicYear;
    this.level = level;
    this.name = name;
}
(注意:如果无法创建对象,为什么要增加序列号?)

非常优雅,对吧?--另一件事是使消息更加具体

无论如何,我认为最好的源代码是整个JDK平台,因为在构造函数中抛出异常是一种常见的模式


正如Luiggi Mendoza在评论中所说,如果你的老师需要一位教授的话

187     public More ...HashMap(int initialCapacity, float loadFactor) {
188         if (initialCapacity < 0)
189             throw new IllegalArgumentException("Illegal initial capacity: " +
190                                                initialCapacity);
191         if (initialCapacity > MAXIMUM_CAPACITY)
192             initialCapacity = MAXIMUM_CAPACITY;
193         if (loadFactor <= 0 || Float.isNaN(loadFactor))
194             throw new IllegalArgumentException("Illegal load factor: " +
195                                                loadFactor);
196 
197         // Find a power of 2 >= initialCapacity
198         int capacity = 1;
199         while (capacity < initialCapacity)
200             capacity <<= 1;
201 
202         this.loadFactor = loadFactor;
203         threshold = (int)(capacity * loadFactor);
204         table = new Entry[capacity];
205         init();
206     }
187公共更多…HashMap(int initialCapacity,float loadFactor){
188如果(初始容量<0)
189抛出新的IllegalArgumentException(“非法初始容量:”+
(容量);
191如果(初始容量>最大容量)
192初始容量=最大容量;
193如果(负载系数=初始容量
198国际通行能力=1;
199同时(容量<初始容量)

200容量我认为这主要是基于观点的。不过我不会直接抛出NullPointerException。我会抛出IllegalArgumentException。不过,明确列出可以抛出的异常类型可能是有意义的。另外,还可以对异常及其发生时间进行javadoc。一般来说,我会尽量避免,但我认为不会his是一个数据验证,所以应该可以。只需查看JDK
HashMap
类实现的代码。检查此构造函数:
public HashMap(int initialCapacity,float loadFactor)
,它包含:
if(initialCapacity<0){抛出新的IllegalArgumentException(“非法初始容量:+initialCapacity”);}
你应该问问你的指导老师为什么会这样想。也许他有很多作者没有的见解。在任何情况下,如果你没有在构造函数中捕捉到错误,你将不得不在别处捕捉到它们,或者当你的对象实际需要对其进行操作时(这可能是对时间和资源的巨大浪费,而这些本可以在早期避免),否则您将不得不希望每个人都知道如何检查这些问题。这也不能保证。相关:对于这种情况,您可以使用
CourseBuilder
类,该类将获取必要的数据来创建
课程
,并在
build()中抛出异常public Course(String name, String code, char level, int academicYear)
{
    if (name == null) {
        throw new NullPointerException("Name can not be null.");
    }
    if (code == null) {
        throw new NullPointerException("Code can not be null.");
    }

    if (indexOf(level, VALID_LEVEL) == -1) {
        throw new InvalidLevelException("Level must be one of " 
            + "characters defined in the public array in Course.");
    }

    if (String.valueOf(academicYear).length() != NUMBER_OF_DIGITS_IN_YEAR) {
        throw new InvalidYearException("Year must be a four digit number!");
    }

    serialNumber = nextSerialNumber++;
    this.code = code;
    this.academicYear = academicYear;
    this.level = level;
    this.name = name;
}
187     public More ...HashMap(int initialCapacity, float loadFactor) {
188         if (initialCapacity < 0)
189             throw new IllegalArgumentException("Illegal initial capacity: " +
190                                                initialCapacity);
191         if (initialCapacity > MAXIMUM_CAPACITY)
192             initialCapacity = MAXIMUM_CAPACITY;
193         if (loadFactor <= 0 || Float.isNaN(loadFactor))
194             throw new IllegalArgumentException("Illegal load factor: " +
195                                                loadFactor);
196 
197         // Find a power of 2 >= initialCapacity
198         int capacity = 1;
199         while (capacity < initialCapacity)
200             capacity <<= 1;
201 
202         this.loadFactor = loadFactor;
203         threshold = (int)(capacity * loadFactor);
204         table = new Entry[capacity];
205         init();
206     }