Java中避免空指针的好轻量级设计模式有哪些?

11

显然,Java编程中最大的问题之一是null和null指针异常。有哪些设计模式可以不会增加太多代码但减少空指针异常的问题呢?


我们真的需要一个空指针检查模式吗?使用像commonsutil这样的东西不应该足够了吗? - kosa
1
“显然是最大的祸根”?NullPointerException是最容易诊断的问题之一。 - Michael Borgwardt
@thinksteep,如果你经常这样做并且可以建立一个好的模式,那么是有益的。特别是如果通常处理方式很冗长的话。 - Joe
我特别想避免编写以下代码:if ((a!=null)&&(a.getB()!=null)&(a.getB().getC()!=null)){ //stuff } - Joe
@MichaelBorgwardt 这个问题很容易诊断,但它很常见,而且你最终会添加很多代码行来避免它。事实上,这可能是需要最多额外代码来解决的问题。 - Joe
8个回答

11

我知道 Google Guava 有很多优秀的好东西,但我不知道它解决了这个问题。 - Joe
空对象模式如何可以减少空指针异常的问题? - UmNyobe
@UmNyobe:如果你有一个对象而不是null,你就不会出现空指针异常。 - Michael Borgwardt
1
是的,但如果出现非常情况,为什么程序还要表现得正常呢? - UmNyobe
@Joe:我只是希望你不要给自己留下一堆麻烦。一个默默绕过错误状态的应用程序比一个大声喊叫和抗议的应用程序更难排除故障。 - pap
@Pap,你已经在其他地方表达了你的观点。如果你深入研究这个解决方案,它并不是一个可以默默忽略空值的解决方案,而是更好地处理它们。 - Joe

3

请习惯于在方法中不返回null对象。

public MyObject bohemianRhapsody(){

   try {
       if(isThisTheRealLife())
           return new MyObject("is this just fantasy");
       else
           return new MyObject("caught in a landslide, no escape from reality");
   } catch(ExampleCatchableException e){
       return new MyObject(""); // instead of return null
   }
}

...
System.out.println(bohemianRhapsody()); // will never print null

这也(有点)被称为空对象模式


这不是空对象模式。空字符串和null之间有区别。调用代码(毕竟你将其公开了)可能非常合理地想要根据返回的内容是null还是空来做出决策。 - George Mauer
@GeorgeMauer,它可以非常合理地直接在界面上使用结果 - 在这种情况下,显示“null”还是什么都不显示更好? - Marcelo
1
@Marcelo - 你的更新更接近于空对象模式。 (假设)MyObject将通过调用ToString在界面上显示 - 你应该返回MyObject(null),并在特殊情况下简单地使ToString()返回空字符串。 这样,调用代码仍然可以检查结果是否为null(可能使用IsNull()方法),但不会出现null异常。 可以参考C#中的Nullable<>类作为一个很好的例子。 - George Mauer

3

3
为什么要避免空指针异常?当你编写代码时,得到 null 而期望其他值是出现问题的首个迹象之一。只有在确认适合时,才应使用诸如 Null Object Pattern 等设计模式。设计模式的最大缺点之一是滥用或误用。
编辑:
我认为减少 null 返回的最佳方法将是增加异常的使用。想想当你试图访问索引为 -1 的元素时,列表返回一个 null 对象,你将会使用像

if(list.get(-1).equals(nullObject))

这样更糟糕。我认为在参数不符合预期或不兼容时引发异常会更好。


更多的检查异常比空指针更好。我不喜欢空指针,因为它们表示有些东西出了问题,但是它们只能在运行时被发现。像 Null Object 模式这样的方式更好,因为你的代码可以跟踪错误并提供逻辑解决方案来解决问题。 - Joe

2
"something definetly not null".equals(maybeNullVar)

vs

maybeNullVar.equals("something definetly not null")

2
我认为这只是个人口味问题,但我会说像Smalltalk/Objective-C这样的语言最大的弊端之一就是它们没有null,并且也没有NullPointerExceptions。我不喜欢“Null object pattern”,事实上我非常痛恨它,因为我发现它使得在没有任何真正好处的情况下,排错和查找错误变得更加困难。Null有一个(通常是坏的)含义,不应该像其他一般状态一样对待。
正如在本主题中提到的那样,NPE非常强大,是捕获句法错误或早期错误的好方法,而if (obj != null)则非常直观。如果你的应用程序在运行时开始生成NPE,则说明你做错了什么,需要修复它。不要试图隐藏异常,而是修复引起异常的任何问题。

空指针异常是一种未经检查的异常。因此,问题在于你直到运行时才会发现问题。最好的做法是在代码中一开始就解决没有值的情况。 - Joe
当然。这就是为什么你要检查是否为空。但我发现可怕的是,有时一个值可能为空却没有引起明确和适当的反应(比如NPE)。在Smalltalk/Obj-c中,“null也是一个对象”的整个概念让我感到非常不安。Null不是一个值,它是null。 - pap
1
但是,如果有一个封装了错误信息的空对象,并在应该设置后使用时抛出已检查的异常,那怎么办呢?检查 null 值的问题在于我们是人类,可能会忘记这样做。Null 基本上破坏了 Java 对象模型。如果您觉得不需要一种语言来提醒您做事情,那么您在具有比 Java 更弱类型的语言中将更加高效。 - Joe

1
这些方法(也可参考Apache commons-lang)可以通过封装字符串处理的空值检查在方法中保留代码语义的方式来减轻空值检查的负担。
public static boolean isBlank(final String str)
{
    return (str == null) || str.isEmpty();
}

public static boolean isNotBlank(final String str)
{
    return !StringUtils.isBlank(str);
}

public static boolean isEqual(final String s1, final String s2)
{
    if (s1 == s2) { return true; }
    if ((s1 == null) || (s2 == null)) { return false; }
    return s1.equals(s2);
}

public static boolean isNotEqual(final String s1, final String s2)
{
    return !StringUtils.isEqual(s1, s2);
}

1

您不必使用任何设计模式。

只需在声明期间初始化变量。

例如:

List<String> names = new ArrayList<String>();
Map<String,String> pairs = new HashMap<String,String>();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接