回答

收藏

在 Java 中避免 NullPointerException

技术问答 技术问答 178 人阅读 | 0 人回复 | 2023-09-12

我用object != null避免的方法很多NullPointerException.
' {2 y$ s" h, S% g$ `1 C替代方案是什么:
5 P* @2 I! A# S8 x' Q

    % f2 y% y5 @* m! b. ?! q
  • if (someobject != null) {    someobject.doCalc()code]               
    1 A$ F: N3 F1 s, R1 ]5 M
  •     解决方案:                                                               
    / b3 j- U$ ]- E( p: j3 X7 P$ A
  •                                                                 对我来说,这听起来像是初级到中级开发人员在某些时候经常面临的一个常见问题:他们要么不知道,要么不信任他们参与的合同,并防御性地过度检查空值。此外,在编写自己的代码时,他们倾向于依靠返回空值来指示某些内容,从而要求调用器检查空值。
    % F3 N3 r. C8 X# d: C2 u, }' g
  • 换句话说,空值检查有两种情况:
    0 g% N  f7 F$ c6 A
  • [ol]; X. m) ?/ ]# L
  • 如果 null 是合同的有效响应;and
    0 Q- W8 r: U+ I+ o1 W
  • 若无有效反应。[/ol](2) 容易assert(断言)或允许失败(如 )NullPointerException)。断言是 1.在4 中添加的一项未充分利用 Java 功能。语法是:[code]assert
    # Y6 o- |! j  l
或者& `$ k. s0 o+ r2 H% ?2 ^
    assert  :
    8 r  M; }( g; H' j% {! z- w; O/ Q
where是布尔表达式,它是一个对象toString()方法的输出将包含在错误中。4 V- _9 \1 [0 K2 P3 }1 B
一个assert抛出一个句子Error(AssertionError若条件不正确)。默认情况下,Java 忽略断言。您可以通过传递选项-ea给 JVM使用断言。您可以使用和禁止单个类别和包。这意味着您可以在开发和测试过程中使用断言验证代码,并在生产环境中禁止它们,尽管我的测试表明断言几乎没有性能影响。
1 j6 V- q4 I+ C' c, Y4 R7 d+ [在这种情况下,不使用断言是可以的,因为代码只会失败,如果使用断言就会发生。唯一的区别是,断言可能发生得更快,以更有意义的方式发生,并的信息,这可能会帮助你找出事故的原因。9 @7 a2 o- Y2 p/ r5 G
(1) 有点难。如果无法控制正在调用的代码,就会陷入困境。null 如果反应有效,必须检查。2 I6 m# K3 \" f. E
然而,如果你真的控制了代码(通常是这样),情况就会有所不同。避免使用空值作为响应。使用返回集合的方法很容易:几乎总是返回空集合(或数组)而不是空值。
/ a" }) b& @9 L8 H& M对于非收藏品来说,可能会更加困难。例如:如果您有这些接口:
5 S+ O2 i- R) o8 f1 V, r$ z. t
    public interface Action {  void doSomething();}public interface Parser {  Action findAction(String userInput);}9 X) b+ t8 T- n& S8 Q2 D# k
Parser 获取原始用户输入并找到要做的事情,也许如果您正在为某事实现命令行界面。现在,如果没有适当的操作,您可以制定返回 null 合同。这导致了你在谈论的空检。0 @8 {% o6 q% `' s' Q1 F0 ]5 ?
另一个解决办法是永不返回 null 而是使用Null 对象模式:
+ g: k& W' _$ k8 b% V7 F" y/ }$ j

    7 Y8 B* j; L& a& D0 r! h
  • public class MyParser implements Parser {  private static Action DO_NOTHING = new Action()      public void doSomething() { / ()* do nothing *  ; public Action findAction(String userInput)      / ...    if ( /* we can't find any actions * {           return DO_NOTHING;   code]比较:
    + m( [) }( W% J5 C! R
  • [code]Parser parser = ParserFactory.getParser();if (parser == null) {  / now what?  // this would be an example of where null isn't (or shouldn't be) a valid response}Action action = parser.findAction(someInput);if (action == null) {  / do nothing} else {  action.doSomething()code]到[code]ParserFactory.getParser().findAction(someInput).doSomething();
    1 E5 z3 |6 k" Y, s# F# w
这是一个更好的设计,因为它导致了更简单的代码。
6 h/ Y  N; F6 ~# {+ a5 {也就是说,findAction() 抛出有意义错误信息的异常方法可能是完全合适的——尤其是当你依赖用户输入时。findAction 方法抛出异常比调用方法抛出简单 NullPointerException 没有解释要好得多。3 m- k( I5 ?/ i; J2 n
[code]try    ParserFactory.getParser().findAction(someInput).doSomething();} catch(ActionNotFoundException anfe)    userConsole.err(anfe.getMessage()code]或者,如果您认为 try/catch 机制太丑,不是什么都不做。您的默认操作应该反馈给用户。. V' X, u9 ^: i. \9 F( }% Q8 V: t
[code]public Action findAction(final String userInput) {    * Code to return requested Action if found */    return new Action()(){        public void doSomething()(){            userConsole.err("Action not found: "   userInput);      code]
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则