简体   繁体   English

在我的特定情况下,我是否应该使用自定义异常?

[英]In my particular situation should I use custom exceptions or not?

I have to make this student repository where exceptions need to be thrwon if certain conditions are not met.如果不满足某些条件,我必须创建这个学生存储库,其中需要抛出异常。 My question is: should I create my own custom exceptions, or should I use the predefined ones?我的问题是:我应该创建自己的自定义异常,还是应该使用预定义的异常? I will leave a portion of my code below我将在下面留下我的一部分代码

public class StudentRepository {

private static List<Student> studentList = new ArrayList<>();
private static Set<Student> studentsByAge = new TreeSet<>(new AgeComparator());
private static Set<Student> studentsByLastName = new TreeSet<>(new LastNameComparator());

public static Student addStudent(String firstName, String lastName, String gender, LocalDate dateOfBirth) {


    if (firstName.trim().isEmpty() || lastName.trim().isEmpty()) {
        throw new NullPointerException("Last name or first name field may be empty");
    } else if (!(gender.equalsIgnoreCase("m") || gender.equalsIgnoreCase("f"))) {
        throw new IllegalArgumentException("Gender should be 'M or 'F");
    } else if (dateOfBirth.isBefore(LocalDate.of(1900, 1, 1)) ||
            dateOfBirth.isAfter(LocalDate.now())) {
        throw new IllegalArgumentException("Date of birth should be between 1900 and current year");
    }

    Student newStudent = new Student(firstName, lastName, dateOfBirth, gender);
    studentList.add(newStudent);
    return newStudent;
}

public static void deleteStudentByCnp(String cnp) {
    Student studentToDelete = null;

    for (Student student : studentList) {
        if (student.getCnp().equals(cnp)) {
            studentToDelete = student;
            studentList.remove(studentToDelete);
            break;
        } else {
            throw new NullPointerException("The student does not exist");
        }
    }
}

You can check Oracle's recommendations on checked vs unchecked exceptions topic which should make it more clear: https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html您可以查看 Oracle 关于已检查与未检查异常主题的建议,这应该更清楚: https : //docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html

and the summary from the page is the following该页面的摘要如下

Here's the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception.这是底线准则:如果可以合理地期望客户端从异常中恢复,请将其设为已检查异常。 If a client cannot do anything to recover from the exception, make it an unchecked exception.如果客户端无法从异常中恢复,请将其设为未经检查的异常。

You can also read more about usage of custom exceptions vs standard ones here: https://stackify.com/java-custom-exceptions/您还可以在此处阅读有关自定义异常与标准异常用法的更多信息: https : //stackify.com/java-custom-exceptions/

Generally it depends on client behaviour - what client can do with this exception.通常这取决于客户端的行为 - 客户端可以用这个异常做什么。 If it's only logging error and nothing more - then IllegalArgumentException should be enough but if you then return this error to client, eg using REST - then it would make sense to create custom exception with proper structure that would be serialized and returned in response to keep consistent structure of errors in response.如果它只是记录错误而仅此而已 - 那么 IllegalArgumentException 应该就足够了,但是如果您随后将此错误返回给客户端,例如使用 REST - 那么创建具有适当结构的自定义异常将是有意义的,该异常将被序列化并返回以响应保持响应错误的一致结构。

Anyway, please do not use NullPointerException besides cases when something is null unexpectedly (ie it's programmer's error).无论如何,请不要使用NullPointerException除了某些意外为 null 的情况(即程序员的错误)。 In your case I would replace NullPointerExceptions with custom exception.在您的情况下,我会用自定义异常替换 NullPointerExceptions。

Assuming these rules (gender must be M or F , etc) are considered preconditions (in that the docs call out: The params you pass must adhere to these rules), the correct exception to throw is IllegalArgumentException .假设这些规则(性别必须是MF等)被视为先决条件(因为文档指出:您传递的参数必须遵守这些规则),抛出的正确异常是IllegalArgumentException Except for a precondition that a param must not be null, in which case NullPointerException is appropriate.除了 param 不能为 null 的先决条件,在这种情况下NullPointerException是合适的。 Talking about recoverability is not appropriate for that kind of exception - the author of a method has no idea if the caller is the kind of code that can 'reasonably recover from the exception'.谈论可恢复性不适用于这种异常——方法的作者不知道调用者是否是那种可以“合理地从异常中恢复”的代码。 There's a decent chance they can't (say, it's text provided over a network and there's no mechanism to signal back to the caller: Err, you're not following the agreed upon spec there, or it's from a config file), so unchecked is probably better here.他们很有可能不能(比如,它是通过网络提供的文本,并且没有机制向调用者发回信号:呃,你没有遵循那里商定的规范,或者它来自配置文件),所以在这里未经检查可能更好。 IllegalArgumentException just fits. IllegalArgumentException恰到好处。

NullPointerException , though, is clearly really bad usage here .但是, NullPointerException在这里显然是非常糟糕的用法 That is to signal a thing is null that wasn't expected to be, and that is all , so don't abuse it like this!那就是表示一个事情是空的,这不是预期的,就是这样,所以不要像这样滥用它!

Note that your code has plenty of problems:请注意,您的代码有很多问题:

  • 2 genders? 2 性别? It's 2021. This probably was never acceptable but certainly isn't now.现在是 2021 年。这可能永远不会被接受,但现在肯定不是。 Why do you need to know the gender of a student?为什么你需要知道学生的性别? To put the right honorific on top of a letter?将正确的敬语放在字母上? Get rid of gender and add a field for 'Honorific' instead.摆脱性别并为“荣誉”添加一个字段。 Various countries have guidelines against asking for gender when it is not relevant.许多国家都有指导方针,禁止在不相关时询问性别。 I doesn't seem relevant here.我在这里似乎无关紧要。 (Honorific might be; if you need that, ask for that). (荣誉可能是;如果您需要,请要求)。
  • If you want ignore that and force 2 genders, then force it , and write an enum instead.如果您想忽略它并强制使用 2 个性别,请强制使用它,然后编写一个枚举。 You want to avoid the entire idea that some inputs can be stated but are invalid - because then you need to keep writing code to react to invalid state.您想避免某些输入可以声明但无效的整个想法 - 因为那样您需要继续编写代码以对无效状态做出反应。 Much better if an object or param simply cannot be wrong.如果一个对象或参数根本不可能是错误的,那就更好了。 An enum cannot be wrong, or at least, can only be wrong if eg it is null, which is a simpler check.枚举不可能是错误的,或者至少,只有在例如它为空时才会是错误的,这是一种更简单的检查。
  • Your 'date' error says 'current year' but actually checks current day.您的“日期”错误显示为“当前年份”,但实际上是在检查当前日期。
  • The error for gender has typos.性别错误有错别字。
  • Your message for lastname/firstname is unclear and doesn't follow java styles.您的姓氏/名字消息不清楚,并且不遵循 Java 样式。 You should state the rule, not the problem.你应该陈述规则,而不是问题。 'First and Last name must not be empty'. '名字和姓氏不得为空'。 There's nothing 'may' about it.没有什么“可能”的。
  • Your delete method will check the first student in the list.您的delete方法将检查列表中的第一个学生。 If its CNP matches, that is deleted, and you're done.如果它的 CNP 匹配,则将其删除,然后就完成了。 If it does not match, your code errors out immediately.如果不匹配,您的代码会立即出错。 It never scans any student other than the very first in the list.除了列表中的第一个之外,它从不扫描任何学生。 That exception throw needs to be outside the for loop.该异常抛出需要在for循环之外。
  • a Map sounds like a better datastructure here; Map在这里听起来像是更好的数据结构; currently your delete code will take longer and longer as there are more and more students.目前,随着学生越来越多,您的删除代码将花费越来越长的时间。
  • While you're making the code more general, the concept of 'first' and 'last' name is dubious as well.当您使代码更通用时,“名字”和“姓氏”的概念也很可疑。 This is good news: It simplifies our lives as developers.这是个好消息:它简化了我们作为开发人员的生活。 Just have a 'full name' field.只需有一个“全名”字段。 Now you no longer have to do the math on how to combine first and last name together.现在,您不再需要计算如何将名字和姓氏组合在一起。 You just print the value of the 'full name' field.您只需打印“全名”字段的值。 If you have a need for a shorter name, then add that as a field instead.如果您需要更短的名称,请将其添加为字段。 Same for gender: Instead of figuring out the right honorific based on gender, just put the value of the 'honorific' field up there.性别也一样:不要根据性别找出正确的敬语,只需将“敬语”字段的值放在那里。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM