Java 将 null 传递给方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32280/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:23:59  来源:igfitidea点击:

Passing null to a method

javanullassert

提问by toolkit

I am in the middle of reading the excellent Clean Code

我正在阅读优秀的清洁代码

One discussion is regarding passing nulls into a method.

一个讨论是关于将空值传递给方法。

public class MetricsCalculator {
    public double xProjection(Point p1, Point p2) {
        return (p2.x - p1.x) * 1.5;
    }
}
...
calculator.xProjection(null, new Point(12,13));

It represents different ways of handling this:

它代表了不同的处理方式:

public double xProjection(Point p1, Point p2) {
    if (p1 == null || p2 == null) {
        throw new IllegalArgumentException("Invalid argument for xProjection");
    }
    return (p2.x - p1.x) * 1.5;
}

public double xProjection(Point p1, Point p2) {
    assert p1 != null : "p1 should not be null";
    assert p2 != null : "p2 should not be null";
    return (p2.x - p1.x) * 1.5;
}

I prefer the assertionsapproach, but I don't like the fact that assertions are turned off by default.

我更喜欢断言方法,但我不喜欢默认情况下关闭断言的事实。

The book finally states:

该书最后指出:

In most programming languages there is no good way to deal with a null that is passed by a caller accidentally. Because this is the case, the rational approach is to forbid passing null by default.

在大多数编程语言中,没有处理调用者意外传递的 null 的好方法。因为是这种情况,合理的做法是默认禁止传递 null。

It doesn't really go into how you would enforce this restriction?

它并没有真正涉及您将如何执行此限制?

Do any of you have strong opinions either way.

你们中的任何人是否有强烈的意见。

采纳答案by Russell Mayor

Both the use of assertions and the throwing of exceptions are valid approaches here. Either mechanism can be used to indicate a programming error, not a runtime error, as is the case here.

在这里使用断言和抛出异常都是有效的方法。任何一种机制都可用于指示编程错误,而不是运行时错误,就像这里的情况。

  • Assertions have the advantage of performance as they are typically disabled on production systems.
  • Exceptions have the advantage of safety, as the check is always performed.
  • 断言具有性能优势,因为它们通常在生产系统上被禁用。
  • 异常具有安全的优点,因为始终会执行检查。

The choice really depends on the development practices of the project. The project as a whole needs to decide on an assertion policy: if the choice is to enable assertions during all development, then I'd say to use assertions to check this kind of invalid parameter - in a production system, a NullPointerException thrown due to a programming error is unlikely to be able to be caught and handled in a meaningful way anyway and so will act just like an assertion.

选择实际上取决于项目的开发实践。整个项目需要决定一个断言策略:如果选择是在所有开发过程中启用断言,那么我会说使用断言来检查这种无效参数 - 在生产系统中,由于以下原因抛出 NullPointerException无论如何,编程错误不太可能以有意义的方式被捕获和处理,因此就像断言一样。

Practically though, I know a lot of developers that don't trust that assertions will be enabled when appropriate and so opt for the safety of throwing a NullPointerException.

但实际上,我知道很多开发人员不相信会在适当的时候启用断言,因此选择抛出 NullPointerException 的安全性。

Of course if you can't enforce a policy for your code (if you're creating a library, for example, and so are dependent on how other developers run your code), you should opt for the safe approach of throwing NullPointerException for those methods that are part of the library's API.

当然,如果您不能为您的代码强制执行策略(例如,如果您正在创建一个库,并且因此依赖于其他开发人员如何运行您的代码),您应该选择安全的方法为那些抛出 NullPointerException作为库 API 一部分的方法。

回答by wvdschel

I generally prefer not doing either, since it's just slowing things down. NullPointerExceptions are thrown later on anyway, which will quickly lead the user to discovering they're passing null to the method. I used to check, but 40% of my code ended up being checking code, at which point I decided it was just not worth the nice assertion messages.

我通常不喜欢这样做,因为它只是放慢了速度。无论如何,稍后会抛出 NullPointerExceptions,这将很快导致用户发现他们将 null 传递给方法。我曾经检查过,但我的 40% 的代码最终都在检查代码,此时我认为这不值得漂亮的断言消息。

回答by Chris Karcher

It doesn't really go into how you would enforce this restriction?

它并没有真正涉及您将如何执行此限制?

You enforce it by throwing an ArgumentExcexceptionif they pass in null.

如果它们传入 null,您可以通过抛出ArgumentException 来强制执行它。

if (p1 == null || p2 == null) {
    throw new IllegalArgumentException("Invalid argument for xProjection");
}

回答by Lasse V. Karlsen

I agree or disagree with wvdschel's post, it depends on what he's specifically saying.

我同意或不同意wvdschel 的帖子,这取决于他具体说的是什么。

In this case, sure, this method will crash on nullso the explicit check here is probably not needed.

在这种情况下,当然,此方法会崩溃,null因此可能不需要此处的显式检查。

However, if the method simply stores the passed data, and there is some other method that you call later that will deal with it, discovering bad input as early as possible is the key to fixing bugs faster. At that later point, there could be a myriad of ways that bad data happened to be given to your class. It's sort of trying to figure out how the rats came into your house after the fact, trying to find the hole somewhere.

但是,如果该方法只是存储传递的数据,并且您稍后会调用一些其他方法来处理它,那么尽早发现错误输入是更快修复错误的关键。稍后,可能有无数种方式将不良数据提供给您的班级。这有点像试图弄清楚老鼠是如何在事后进入你的房子,试图在某个地方找到洞。

回答by Brian Matthews

I prefer the use of assertions.

我更喜欢使用断言。

I have a rule that I only use assertions in public and protected methods. This is because I believe the calling method should ensure that it is passing valid arguments to private methods.

我有一个规则,我只在公共和受保护的方法中使用断言。这是因为我相信调用方法应该确保将有效参数传递给私有方法。

回答by aku

General rule is if your method doesn't expect nullarguments then you should throw System.ArgumentNullException. Throwing proper Exceptionnot only protects you from resource corruption and other bad things but serves as a guide for users of your code saving time spent debugging your code.

一般规则是,如果您的方法不需要null参数,那么您应该抛出System.ArgumentNullException。正确抛出Exception不仅可以保护您免受资源损坏和其他不良事件的影响,还可以为您的代码用户提供指导,从而节省调试代码的时间。

Also read an article on Defensive programming

另请阅读有关防御性编程的文章

回答by Shaun Austin

@Chris Karcher I would say absolutely correct. The only thing I would say is check the params separately and have the exeption report the param that was null also as it makes tracking where the null is coming from much easier.

@Chris Karcher 我会说绝对正确。我唯一要说的是单独检查参数,并让 exeption 报告为空的参数,因为它使跟踪空值的来源变得更加容易。

@wvdschel wow! If writing the code is too much effort for you, you should look into something like PostSharp(or a Java equivalent if one is available) which can post-process your assemblies and insert param checks for you.

@wvdschel 哇!如果编写代码对您来说太费力了,您应该研究类似PostSharp(或 Java 等价物,如果有的话)之类的东西,它可以对您的程序集进行后处理并为您插入参数检查。

回答by Jorge Córdoba

Although it is not strictly related you might want to take a look to Spec#.

虽然它不是严格相关的,但您可能想看看Spec#

I think it is still in development (by Microsoft) but some CTP are available and it looks promising. Basically it allows you to do this:

我认为它仍在开发中(由 Microsoft),但一些 CTP 可用,看起来很有希望。基本上它允许你这样做:

  public static int Divide(int x, int y)
    requires y != 0 otherwise ArgumentException; 
  {
  }

or

或者

  public static int Subtract(int x, int y)
    requires x > y;
    ensures result > y;
  {
    return x - y;
  } 

It also provides another features like Notnull types. It's build on top of the .NET Framework 2.0 and it's fully compatible. The syntaxt, as you may see, is C#.

它还提供了另一个特性,如 Notnull 类型。它建立在 .NET Framework 2.0 之上,并且完全兼容。如您所见,语法是 C#。

回答by rcreswick

Spec# looks very interesting!

规格#看起来很有趣!

When something like that isn't available, I generally test non-private methods with a run-time null-check, and assertions for internal methods. Rather than code the null check explicitly in each method, I delegate that to a utilities class with a check null method:

当类似的东西不可用时,我通常使用运行时空检查和内部方法的断言来测试非私有方法。我没有在每个方法中明确编码空检查,而是将其委托给具有检查空方法的实用程序类:

/**
 * Checks to see if an object is null, and if so 
 * generates an IllegalArgumentException with a fitting message.
 * 
 * @param o The object to check against null.
 * @param name The name of the object, used to format the exception message
 *
 * @throws IllegalArgumentException if o is null.
 */
public static void checkNull(Object o, String name) 
    throws IllegalArgumentException {
   if (null == o)
      throw new IllegalArgumentException(name + " must not be null");
}

public static void checkNull(Object o) throws IllegalArgumentException {
   checkNull(o, "object");
} 

// untested:
public static void checkNull(Object... os) throws IllegalArgumentException {
   for(Object o in os) checkNull(o);  
}

Then checking turns into:

然后检查变成:

public void someFun(String val1, String val2) throws IllegalArgumentException {
   ExceptionUtilities.checkNull(val1, "val1");
   ExceptionUtilities.checkNull(val2, "val2");

   /** alternatively:
   ExceptionUtilities.checkNull(val1, val2);
   **/

   /** ... **/
} 

Thatcan be added with editor macros, or a code-processing script. Edit:The verbose check could be added this way as well, but I think it's significantly easier to automate the addition of a single line.

可以通过编辑宏或代码处理脚本添加。 编辑:也可以通过这种方式添加详细检查,但我认为自动添加一行要容易得多。

回答by Chris Conway

Also not of immediate use, but related to the mention of Spec#... There's a proposal to add "null-safe types" to a future version of Java: "Enhanced null handling - Null-safe types".

也不是立即使用,但与 Spec# 的提及有关......有一个建议将“空安全类型”添加到 Java 的未来版本:“增强空处理 - 空安全类型”

Under the proposal, your method would become

根据该提案,您的方法将变为

public class MetricsCalculator {
    public double xProjection(#Point p1, #Point p2) {
        return (p2.x - p1.x) * 1.5;
    }
}

where #Pointis the type of non-nullreferences to objects of type Point.

其中#Point是对 typenull对象的非引用的类型Point

回答by Cem Catikkas

Thwrowing C# ArgumentException, or Java IllegalArgumentExceptionright at the beginning of the method looks to me as the clearest of solutions.

在方法的开头抛出 C#ArgumentException或 JavaIllegalArgumentException在我看来是最清晰的解决方案。

One should always be careful with Runtime Exceptions - exceptions that are not declared on the method signature. Since the compiler doesn't enforce you to catch these it's really easy to forget about them. Make sure you have some kind of a "catch all" exception handling to prevent the software to halt abruptly. That's the most important part of your user experience.

人们应该始终小心运行时异常 - 未在方法签名上声明的异常。由于编译器不会强制您捕获这些,因此很容易忘记它们。确保您有某种“捕获所有”异常处理以防止软件突然停止。这是用户体验中最重要的部分。