V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yibo2018
V2EX  ›  程序员

Java 中 null > 0 为什么要报错,怎么用语法糖或者 JDK 封装的方法避免

  •  1
     
  •   yibo2018 · 2023-05-19 16:13:40 +08:00 · 3864 次点击
    这是一个创建于 555 天前的主题,其中的信息可能已经有所发展或是发生改变。
    if (a > 0) { }
    
    if (Objects.compare(a, 0L, Long::compareTo) > 0) {        }
    
    Exception in thread "main" java.lang.NullPointerException
    

    上面这样写如果 a 是 null 就都会报错

    一般写法是这样可以避免

    if (a != null && a > 0) { }
    ···
    
    但我实在不想每次遇到都写一遍判空逻辑
    null 和 0 本来就不相等,为啥还要报错
    我想找一个 JDK 封装的方法去解决,但没找到
    第 1 条附言  ·  2023-05-19 16:53:20 +08:00

    这种就是jdk自己封装的

    Strings.isBlank()
    
    public static boolean isBlank(final String s) {
            if (s == null || s.isEmpty()) {
                return true;
            }
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if (!Character.isWhitespace(c)) {
                    return false;
                }
            }
            return true;
        }
    
    
    41 条回复    2023-05-22 11:49:10 +08:00
    yibo2018
        1
    yibo2018  
    OP
       2023-05-19 16:15:52 +08:00
    ```
    Comparator<Long> comparator = Comparator.nullsFirst(Long::compareTo);
    if (comparator.compare(null, 0L) > 0) {
    ```

    chat gpt 的答案
    xiaohundun
        2
    xiaohundun  
       2023-05-19 16:21:17 +08:00
    那你不用包装类,考虑处理 0 值呢?
    JYii
        3
    JYii  
       2023-05-19 16:22:54 +08:00   ❤️ 1
    Optional.ofNullable(a)
    .filter(i -> i > 0)
    .ifPresentOrElse("a>0", "a is null || a<=0");
    xiaohundun
        4
    xiaohundun  
       2023-05-19 16:23:02 +08:00
    @xiaohundun 我的意思是这本来就是包装类和原始类型的区别,别人用包装类是因为 null 和 0 有不一样的逻辑,而你这里看起来 null 、0 是一样的逻辑,那你完全可以不用包装类,那就不用判空了
    nitmali
        5
    nitmali  
       2023-05-19 16:23:22 +08:00
    Optional.ofNullable(a).orElse(0) > 0
    crazyweeds
        6
    crazyweeds  
       2023-05-19 16:28:42 +08:00
    我觉得挺好,null 就是 null ,别搞那么多语法糖,没啥用,增加记忆负担。
    jmc891205
        7
    jmc891205  
       2023-05-19 16:30:56 +08:00
    类型不一样咋比
    null > 0 应该返回 true 还是 false 呢
    luhongfei66
        8
    luhongfei66  
       2023-05-19 16:31:13 +08:00
    null 没办法 0 做比较,null 当成大于 0 或者小于 0 都不适合,编译器怎么能知道你的业务呢
    nothingistrue
        9
    nothingistrue  
       2023-05-19 16:32:46 +08:00
    去了解一下基本类型的自动封装解装。你这本事就是语法糖弄出来的问题,在想加新的语法糖就只会越加问题越多。
    hidemyself
        10
    hidemyself  
       2023-05-19 16:35:12 +08:00   ❤️ 1
    你要先定义 null 和 0 的关系,才能给你继续,否则只能给你 NPE
    SilentRhythm
        11
    SilentRhythm  
       2023-05-19 16:40:00 +08:00
    3L 正解
    yazinnnn
        12
    yazinnnn  
       2023-05-19 16:51:32 +08:00   ❤️ 9
    null>0
    false

    null<0
    false

    null==0
    false

    null>=0
    true

    null<=0
    true

    --------
    js 行为
    koloonps
        13
    koloonps  
       2023-05-19 16:53:31 +08:00
    基本数据类型才能够直接比较大小,Integer 比较大小会自动转 int.null 没有对应的值自然会 NPE.jdk1.5 开始支持泛型和自动装箱拆箱,这个版本之后才会有 NPE 问题
    Leviathann
        14
    Leviathann  
       2023-05-19 16:58:05 +08:00
    因为 null 是 null 类型的单例
    而一般的强类型语言只有数字相关的类型才支持 compare 运算符

    所以是支持类型自动转换的弱类型语言或者是支持操作符重载的语言才能做到
    momocraft
        15
    momocraft  
       2023-05-19 16:58:56 +08:00
    JS 自动乱转被黑了一亿年 建议学用 Optional
    coyoteer
        16
    coyoteer  
       2023-05-19 16:59:31 +08:00
    直接 if (a && a > 0) { }不行吗
    yibo2018
        17
    yibo2018  
    OP
       2023-05-19 17:00:51 +08:00
    @coyoteer 当然可以,但是我经常忘记 a 判空
    CDuXZMAPgHp1q9ew
        18
    CDuXZMAPgHp1q9ew  
       2023-05-19 17:05:39 +08:00
    明确不能为 null 的为什么不用 long 要用 Long 呢
    nba2k9
        19
    nba2k9  
       2023-05-19 17:11:51 +08:00
    Java 好就好在没有那么多语法糖
    yibo2018
        20
    yibo2018  
    OP
       2023-05-19 17:12:17 +08:00
    @nothingistrue 基本类型的自动封装解装,我目前的理解就是的 int -> Integer 互相自动转换
    然后每个基本类型有自己定义对于运算符的逻辑

    请问我的理解,你打多少分,100 分满分的话
    crazyweeds
        21
    crazyweeds  
       2023-05-19 17:14:27 +08:00
    @momocraft 深有同感,感觉 js 一直在走极端,明明只要一个强类型,然后搞出了 ts ,开始有人吐槽了。作为一个 java 写 js ,我觉得最难写的就是判断,各种出乎意料的结果。
    crazyweeds
        22
    crazyweeds  
       2023-05-19 17:15:41 +08:00
    @yazinnnn 感动哭了,JS 判断行为真的让人无语。
    Still4
        23
    Still4  
       2023-05-19 17:17:35 +08:00
    用 long 不要用 Long ,你既然用了 Long ,那么说明有需求要区分 null 和 0
    iyiluo
        24
    iyiluo  
       2023-05-19 17:19:58 +08:00
    null 和 0 能比较才是大问题吧,null 表示没赋值,未初始化,怎么能拿来比较
    yibo2018
        25
    yibo2018  
    OP
       2023-05-19 17:20:11 +08:00
    @Still4 怪我没说清,用 Long 是因为在 HashMap 里面
    DinnyXu
        26
    DinnyXu  
       2023-05-19 17:20:26 +08:00
    我在想一个问题,已知变量 a 是数字类型,那么这个变量在判断的时候是否可以有默认值来代替呢,这样就可以进入你的 if 判断了啊。比如你数据库查询出来的 a 是 null 那么判断是否 > 0 肯定是会报错的,你数据库不能设置默认值吗。
    githmb
        27
    githmb  
       2023-05-19 17:22:57 +08:00   ❤️ 1
    我的建议是换 Kotlin ,保证参数签名是 Long 的函数不会被 null 调用
    qping
        28
    qping  
       2023-05-19 17:25:06 +08:00
    你可以参数定义为 int a
    hangszhang
        29
    hangszhang  
       2023-05-19 17:28:29 +08:00
    没参加考试是 null ,考了 0 分是 0 ,这就是包装类最大的意义,区分 0 和 null
    dcsuibian
        30
    dcsuibian  
       2023-05-19 17:33:23 +08:00
    null 是空,什么都没有怎么比
    ThreeK
        31
    ThreeK  
       2023-05-19 17:36:30 +08:00
    既然都报了 NullPointerException 那就是变量有 null 的情况,去处理 null 的场景,自己定义 null 和 0 比较的结果。
    要是代码能百分百确定不是 null ,那你担心什么抛异常。
    oldshensheep
        32
    oldshensheep  
       2023-05-19 17:56:23 +08:00
    语法糖用 manifold ,甜死我啦。

    你这个用 manifold 好像不能实现,但是可以用扩展方法实现一个类似解决方案
    ```java
    public class DemoApplication {
    public static void main(String[] args) {
    Long num = null;
    num.greater(1).print();
    }
    }
    ```
    虽然 num 是 null 但是不会有 NPE ,实际上就是调用你写的静态的扩展方法

    运行结果是 true
    greater 是扩展方法,返回一个 Boolen
    print 是扩展方法,调用 sout

    你这个就直接
    a.greater(0)
    oldshensheep
        33
    oldshensheep  
       2023-05-19 17:57:39 +08:00
    @oldshensheep 上面输出结果说错了,结果是 false
    Still4
        34
    Still4  
       2023-05-19 18:14:08 +08:00
    @yibo2018 map 的话我觉得需要在写入的时候检查 null 的情形,读取的时候就不需要担心 npe 了
    Aynamic
        35
    Aynamic  
       2023-05-19 18:20:49 +08:00
    不要用包装类就不会,用包装类就 equals
    Ericcccccccc
        36
    Ericcccccccc  
       2023-05-19 18:52:26 +08:00
    因为 java 里面 0, 1 这种数字很独特, 是个"基本类型",

    a 作为一个对象, 想和基本类型做大小比较, 需要先转成基本类型, 而 null 是转不过去的
    CLMan
        37
    CLMan  
       2023-05-19 19:23:28 +08:00
    别想太多,纯粹是 JS 设计太烂而已。

    null 与 0 之间转换本来就不符合逻辑,各种语言都给你来这种 feature ,而且还不保持一致,你如果是个多语言用户你咋办,死记硬背这些莫名其妙的无聊规则吗?
    nothingistrue
        38
    nothingistrue  
       2023-05-19 21:52:16 +08:00
    @yibo2018 #20 a 是 Long 的时候,a > 0 在编译时会被转换为 a.longValue > 0 (实际情况可能只是编译后等效而不是先转换再编译,但可以先这么认为)。原本 null > 0 ,或者对量变量 obj > 0 ,都是编译错误,8 个封装类型是加了语法糖,才能这么写。

    知道以上情况,会更容易定位到 NullPointerException “> 0” 没有关系,抛出它的地方是 a.longValue 的时候 a 是 null 。这只是一个很普通但很难处理的 NPE 问题。对于你这种从别的地方接过来的变量(不是你能控制的变量)来说,你只能判断它给你的是不是 null ,但不能控制它不给你 null ,所以是铁定要做 null 判断的。

    如果你只是需要代码更好写 /看,而不是避开 null 判断,那还是有办法的。可以写成这样,if ( requestNonNullOrDefult(a, -1) > 0) 。requestNonNullOrDefult 就需要你自己提供,或者找第三方工具包了,JDK 是没有的。JDK 8 以后用了另一种套路来解决 NPE 问题,它要求方法返回一定不会是 null 的对象,要么是确实不会是 null 的对象,要么是可能为 empty 的 Optiona<T> 对象。
    jim9606
        39
    jim9606  
       2023-05-20 12:38:45 +08:00
    因为算术运算符与 null 运算,不管是返回 null 还是 false 都不合常理,例如 == 和 != 会同时返回 null/false
    你需要的是默认值,将需要比较的 nullable 变量转为 not nullable ,例如 C#的 null 合并运算符 ?? 和 ??=
    ```
    (someVar ??= -1) > 0
    ```
    不过关系运算符支持 null 倒是合理的。
    blankmiss
        40
    blankmiss  
       2023-05-20 15:17:56 +08:00
    你没有用过 Optional 吗
    AoEiuV020
        41
    AoEiuV020  
       2023-05-22 11:49:10 +08:00
    我项目中有大量这种操作,主要是服务器接口使用整数 01 代表 false 和 true ,
    这边处理是直接封装两个方法用来转换,
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3040 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 00:10 · PVG 08:10 · LAX 16:10 · JFK 19:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.