zoukankan      html  css  js  c++  java
  • 在Java中,return null 是否安全, 为什么?

    Java代码中return value 为null 是不是在任何情况下都可以,为什么不会throw NullPointerException?


    Java语言层面:null值自身是不会引起任何问题的。它安安静静的待在某个地方(局部变量、成员字段、静态字段)不会有任何问题;它从一个地方被搬运到另一个地方也不会有任何问题(变量赋值、返回值等)。唯一会因为null值而引起NullPointerException的动作是“解引用”(dereference)——也就是通过这个引用要对其引用的对象做操作。俗话说就是所有隐含“obj.xxx”的操作中,obj为null值的情况。
    在Java里,下述操作隐含对引用的解引用:


     读字段(字节码 getfield):x.y,当x为null时抛NPE;
        写字段(字节码 putfield):x.y = z,当x为null时抛NPE。注意:z的值是什么没关系;
        读数组长度(字节码 arraylength):a.length,当a为null时抛NPE;
        读数组元素(字节码 <x>aload,<x>为类型前缀):a[i],当a为null时抛NPE;
        写数组元素(字节码 <x>astore,<x>为类型前缀):a[i] = x,当a为null时抛NPE。注意:x的值时什么没关系;
        调用成员方法(字节码 invokevirtual、invokeinterface、invokespecial):obj.foo(x, y, z),当obj为null时抛NPE。注意:参数的值是什么没关系;
        增强for循环(也叫foreach循环):
            对数组时(实际隐含a.length操作):for (E e : a) { ... } , 当a为null时抛NPE;
            对Iterable时(实际隐含对Iterable.iterator()的调用):for (E e : es) { ... } ,当es为null时抛NPE;
        自动拆箱(实际隐含 <XXX>.<xxx>Value() 的调用,<XXX>为包装类型名,<xxx>为对应的原始类型名): (int) integerObj,当integerObj为null时抛NPE;
        对String做switch(实际隐含的操作包含对String.hashCode()的调用):switch (s) { case "abc": ... } ,当s为null时抛NPE;
        创建内部类对象实例(字节码 new,但这里特指创建内部类实例的情况):outer.new Inner(x, y, z),当outer为null时抛NPE;
        抛异常(字节码 athrow):throw obj,当obj(throw表达式的参数)为null时抛NPE;
        用synchronized关键字给对象加锁(字节码 monitorenter / monitorexit):synchronized (obj) { ... },当obj为null时抛NPE。


    Java语言里所有其它语法结构都不会因为null值而隐含抛NPE的语义。当然,用户可以在自己需要的地方显式检查null值然后自己抛出NPE,就像:


    1. java.util.Objects.requireNonNull(Object)
    2. /**
    3. * Checks that the specified object reference is not {@code null}. This
    4. * method is designed primarily for doing parameter validation in methods
    5. * and constructors, as demonstrated below:
    6. * <blockquote><pre>
    7. * public Foo(Bar bar) {
    8. * this.bar = Objects.requireNonNull(bar);
    9. * }
    10. * </pre></blockquote>
    11. *
    12. * @param obj the object reference to check for nullity
    13. * @param <T> the type of the reference
    14. * @return {@code obj} if not {@code null}
    15. * @throws NullPointerException if {@code obj} is {@code null}
    16. */
    17. public static <T> T requireNonNull(T obj) {
    18. if (obj == null)
    19. throw new NullPointerException();
    20. return obj;
    21. }

    自己主动throw new NullPointerException()这种情况JVM管不着,用户代码主动指定的,用户想怎么搞就怎么搞。


    趣味题:在Java语言里,只使用Java语言及标准库的功能而不依赖第三方库,检查一个引用obj是否为null并在null时抛NPE的代码是什么?
    答案:obj.getClass()。这是因为getClass()是java.lang.Object类上的方法,因而无论什么引用类型都可以使用。这在Java源码层面和在Java字节码层面上都是最短的。
    当然这是个很邪恶的歪招,然而在OpenJDK的标准库内部实现中并不少见。大家…还是用Objects.requireNonNull()就好了.


    return null主要多了一个麻烦,凡是调用它的地方,都要想一想,是不是要判断if (xxx == null),这样代码不够优雅。


    语言层面上讲,返回null没有任何问题,大家都赞同。
    工程实践中,返回null是否就是个不好的习惯?我倒不这么认为。我的观点是,所有的方法调用,无论是自己工程的内部类方法还是第三方包中的方法,除非对方在Java Doc中显式的说明了不会返回空,其它情况都应该怀疑有返回空指针的可能性。多一个判断并没有什么不好,还能大大增加代码的健壮性。在另一方面,方法的编写者也应该仔细的维护Java Doc,如果会返回空指针,那应该说明原因和语义,让调用者有章可依。

  • 相关阅读:
    codeforces 455B A Lot of Games(博弈,字典树)
    HDU 4825 Xor Sum(二进制的字典树,数组模拟)
    hdu 1800 Flying to the Mars(简单模拟,string,字符串)
    codeforces 425A Sereja and Swaps(模拟,vector,枚举区间)
    codeforces 425B Sereja and Table(状态压缩,也可以数组模拟)
    HDU 4148 Length of S(n)(字符串)
    codeforces 439D Devu and Partitioning of the Array(有深度的模拟)
    浅谈sass
    京东楼层案例思维逻辑分析
    浅谈localStorage和sessionStorage
  • 原文地址:https://www.cnblogs.com/jpfss/p/9366182.html
Copyright © 2011-2022 走看看