Java :如何处理空指针? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
sandman511
V2EX    程序员

Java :如何处理空指针?

  •  1
     
  •   sandman511 2019-12-31 11:16:04 +08:00 6281 次点击
    这是一个创建于 2113 天前的主题,其中的信息可能已经有所发展或是发生改变。
    Integer code = getCode(); String codeMeaning = code == null ? null : code == 1 ? "你好" : code == 2 ? "你好好" : code == 3 ? "你好好好"; 

    请各大佬帮忙修改这段代码
    code == null ? null 看起来有点怪怪的

    第 1 条附言    2019-12-31 12:22:39 +08:00

    看了大家的建议 收获颇丰
    我比较喜欢简短一点的代码(在不影响可读性的情况下) 所以比较喜欢三元。。大家轻喷
    因为业务原因 code=1d的情况下 codeMeaning不一定是”你好“,所以不能使用枚举类或者Map
    目前我采用了9楼的写法 代码美观且解决了空指针的问题(楼上几位的代码也很好)
    但这样写代码从4行增加到了9行,有没有更简洁且美观的写法。
    大家轻喷哈,刚毕业。。啥都不懂

    第 2 条附言    2019-12-31 14:28:51 +08:00

    为了方便大家理解真正的需求,更新下简化版的实际代码:

    //方法1 Integer unit = getUnit (type1); String transferredUnit = unit == null ? null : unit == 1 ? "kg" : unit == 2 ? "g" : unit == 3 ? "t"; 
    //方法2 Integer unit = getUnit (type2); String transferredUnit = unit == null ? null : unit == -1 ? "kg" : unit == 0 ? "g" : unit == 1 ? "t"; 
    //方法3 Integer unit = getUnit (type3); String transferredUnit = unit == null ? null : unit == 4 ? "kg" : unit == 5 ? "g" : unit == 6 ? "t"; 

    这样的情况用枚举类是化简为烦了吧应该,因为要针对不同type创建多个枚举类
    用Map或者直接switch应该是比较好的方法

    第 3 条附言    2019-12-31 14:42:20 +08:00

    Integer unit = getUnit (type) 这个方法是从一个远古软件生成的txt文档中提取 单位(数字格式)
    不同的unit对应什么含义,需要查阅PDF文档来翻译,有很多不同情况
    大家不要纠结为什么不统一unit与transferredUnit的对应关系哈,这个我无能为力...

    57 条回复    2020-01-01 18:31:04 +08:00
    avk458
        1
    avk458  
       2019-12-31 11:25:38 +08:00
    三元表达式还能这样玩儿?
    按照这个`codeMeaning`的意思来用 switch 是不是更好?
    包装类比较是不是应该用 equals ?
    pmispig
        2
    pmispig  
       2019-12-31 11:27:02 +08:00   7
    谁写的,先把他头锤爆
    Lin0936
        3
    Lin0936  
       2019-12-31 11:28:53 +08:00
    // TODO: Bullshit
    sandman511
        4
    sandman511  
    OP
       2019-12-31 11:34:59 +08:00
    @pmispig 实不相瞒。。我写的。。
    manami
        5
    manami  
       2019-12-31 11:36:53 +08:00 via Android
    Objects.equals(a, b)
    optional
        6
    optional  
       2019-12-31 11:37:00 +08:00   1
    // 第一种提前返回
    ```
    if (Objects.isNull(code)) {
    return null;
    }
    //switch or if
    ```
    //第二种,
    ```
    Optional.ofNullable(code).map(code->{
    //switch or if
    }).orElse(null);
    ```
    passerbytiny
        7
    passerbytiny  
       2019-12-31 11:37:08 +08:00
    一,Java 没有指针;
    二,三元连接符嵌套使用是大忌;
    三,if(some == null) { //bulabula when null }else{ //bulabula when not null},或者 if(some != null){bulabula},或者 some.ifPresent((value)->{/bulabula}), 是良好的编码习惯;
    四,请善用默认值:
    Integer code = getCode();
    String codeMeaning == null ;// 或者 "默认值"
    if(code != null){
    switch (code.intValue()){
    case 1 : codeMeaning = "你好"; break;
    // ......
    }
    }
    sandman511
        8
    sandman511  
    OP
       2019-12-31 11:38:17 +08:00
    @avk458 我嫌 switch 写起来太麻烦了 这个逻辑比较简单 就三行 所以用了三元。。。请教一下三元不能这样用吗?
    确实该用 equals,但是 code 可能为 null,equals 可能抛空指针。。所以不知道该咋办了
    lff0305
        9
    lff0305  
       2019-12-31 11:40:35 +08:00   2
    ```
    Optional<Integer> code = Optional.ofNullable(getCode());
    String s = code.map(c -> {
    switch (c) {
    case 1: return "one";
    case 2: return "two";
    }
    return "other";
    }).orElse(null);
    ```
    lovelive1024
        10
    lovelive1024  
       2019-12-31 11:44:24 +08:00
    Map<Integer, String> map = new ....
    codeMeaning = map.get(code);
    U7Q5tLAex2FI0o0g
        11
    U7Q5tLAex2FI0o0g  
       2019-12-31 11:44:46 +08:00
    实不相瞒,三元这么嵌套不加括号的,除了傻逼笔试题外,工作中这样写的同事我会打死他(不是不能嵌套,你得加括号增加可读性)
    lihongjie0209
        12
    lihongjie0209  
       2019-12-31 11:54:00 +08:00
    不加括号就是作死
    w292614191
        13
    w292614191  
       2019-12-31 11:55:22 +08:00
    我感觉比楼上那些 if else switch 好看多了。

    都是些秀无意义代码的。

    你看看 7、9 楼,

    硬是加长代码,毫无意义。
    Jimmy2Angel
        14
    Jimmy2Angel  
       2019-12-31 11:58:35 +08:00
    @passerbytiny 一,你真是个合格的杠精
    ipwx
        15
    ipwx  
       2019-12-31 12:01:09 +08:00
    private static final String[] lookup = {null, "你好", "你好好", "你好好好"};
    String codeMeaning = lookup[code != null? code.intValue() : 0];

    https://ideone.com/7rXSyK
    matepi
        16
    matepi  
       2019-12-31 12:11:15 +08:00 via iPhone
    enum 特性都多少年了吧
    banmuyutian
        17
    banmuyutian  
       2019-12-31 12:11:53 +08:00   1
    @w292614191
    “硬是加长代码,毫无意义。”?
    等你看到那些难以阅读维护的代码就知道代码规范的重要性了
    micean
        18
    micean  
       2019-12-31 12:12:24 +08:00
    挺清晰的,加啥括号?有换行和缩进还不够吗?
    lhx2008
        19
    lhx2008  
       2019-12-31 12:14:49 +08:00 via Android
    enum 吧,或者 map
    code 的话,null 就整个-1 呗,null 来 null 去的
    wysnylc
        20
    wysnylc  
       2019-12-31 12:18:23 +08:00
    optional+switch,或者用 java 13 还是 14 的新 switch
    kkkkkrua
        21
    kkkkkrua  
       2019-12-31 12:20:02 +08:00 via iPhone
    switch 不就好了么,用 default 处理 null
    sagaxu
        22
    sagaxu  
       2019-12-31 12:33:11 +08:00 via Android
    应该用 int,避免 Integer,code 增加一项表示原来用 null 表示的情况。其实用 enum 不是更好吗?
    Sqpan2
        23
    Sqpan2  
       2019-12-31 12:35:54 +08:00 via Android
    做个枚举不香吗?
    sandman511
        24
    sandman511  
    OP
       2019-12-31 12:43:05 +08:00
    @Sqpan2
    @sagaxu
    @lhx2008
    @matepi
    不能用枚举哈,因为 code=1 不一定代表就是”你好“ 只是在这个地方等于”你好"
    在另一个方法里可能就是”你好好好“
    除非创建 7、8 个枚举类,每个枚举类中就三个参数。。
    itechify
        25
    itechify  
    PRO
       2019-12-31 13:04:03 +08:00 via Android
    var table=new HashMap<Integer,String>(){
    {
    put(k1,v1);
    put(k2,v2);
    // ...
    }
    };

    table.get(xx)
    zzzHas
        26
    zzzHas  
       2019-12-31 13:04:07 +08:00
    如果能提高阅读性, 代码长点就长点.
    looseChen
        27
    looseChen  
       2019-12-31 13:26:14 +08:00
    别特么的玩些花里胡哨的玩意
    wesnow
        28
    wesnow  
       2019-12-31 13:26:40 +08:00 via Android
    代码更容易阅读比代码的长短重要得多,甚至可以说除非是非常极端的情况(比如有个地方确实对性能要求很高,这里就可能牺牲部分阅读性),否则都应该把代码更容易阅读更容易理解放在第一位。
    qyvlik
        29
    qyvlik  
       2019-12-31 13:43:16 +08:00
    @ipwx #15 这种查表法可还行。省去 if, switch 的逻辑判断。
    wc951
        30
    wc951  
       2019-12-31 13:45:54 +08:00 via Android
    java8 的 optional 是最优雅的
    1et
        31
    1et  
       2019-12-31 13:50:43 +08:00
    int a = 1,b=2,c=3;
    int d = a+++b+++c;
    palmers
        32
    palmers  
       2019-12-31 13:59:27 +08:00
    按照你回复的#24 我觉得可以使用枚举区分调用类别, 然后返回字符串抽象为方法 应该可以达到你的目的, 这么用确实不太好 除了秀也没有达到简洁的目的, 维护会越来越乱 临时用一下就没什么了
    不知道你真是的需求是什么 就目前你暴露的意愿 我觉得 枚举+抽象可以很好的解决这个问题 也符合开闭原则
    ymz
        33
    ymz  
       2019-12-31 14:09:37 +08:00
    @kkkkkrua null 的话报空指针错误,到不了 default
    guyeu
        34
    guyeu  
       2019-12-31 14:10:15 +08:00   1
    String result = switch (Objects.requireNonNullElse(code, 0)) {
    case 0 -> null;
    case 1 -> "你好";
    case 2 -> "你好好";
    case 3 -> "你好好好";
    default -> throw new UnsupportedOperationException();
    };
    kkkkkrua
        35
    kkkkkrua  
       2019-12-31 14:12:16 +08:00
    @ymz #33 学到了,谢谢
    hhhsuan
        36
    hhhsuan  
       2019-12-31 14:21:15 +08:00
    代码的首要作用是给人看,只是随便可以运行一下。
    oaix
        37
    oaix  
       2019-12-31 14:24:57 +08:00
    Optional 一般只建议用在方法的返回值。
    ilumer
        38
    ilumer  
       2019-12-31 14:29:36 +08:00
    optional+enum 或者 optional+map 在 map 里面写 if else 的逻辑
    sandman511
        39
    sandman511  
    OP
       2019-12-31 14:30:16 +08:00
    @palmers 我又在主贴 APPEND 了一下真正的需求
    earther01
        40
    earther01  
       2019-12-31 14:39:05 +08:00
    @oaix 为啥呢,是效率不高吗?
    oaix
        41
    oaix  
       2019-12-31 14:47:05 +08:00
    wutiantong
        42
    wutiantong  
       2019-12-31 14:50:57 +08:00
    从 append 的代码来看,你应该把 Integer unit + String transferredUnit 这两样东西 wrap 成一个简单的 class,不妨就还叫 unit 好了,数字和字符串作为 unit 这个 class 的两个成员属性。

    你的 getUnit(type) 应该直接返回这个 unit class。
    palmers
        43
    palmers  
       2019-12-31 15:25:29 +08:00   1
    public enum UnitOfWeight {
    KG("kg") {
    @Override
    public boolean match(int unit) {
    return false;
    }
    },
    GRAM("g") {
    @Override
    public boolean match(int unit) {
    return false;
    }
    },
    TON("t") {
    @Override
    public boolean match(int unit) {
    return false;
    }
    },
    UNKNOWN("x-0"){
    @Override
    public boolean match(int unit) {
    return false;
    }

    @Override
    public boolean unknown() {
    return true;
    }
    };


    /**
    * e.g. kg, g, t
    */
    @Getter
    private String note;

    static UnitOfWeight[] units = UnitOfWeight.values();

    /**
    * kg's enums
    */
    static int[] kgs = {1, -1, 4};
    /**
    * gram's enums
    */
    static int[] grams = {2, 0, 5};
    /**
    * ton's enums
    */
    static int[] tOns= {3, 1, 6};

    UnitOfWeight(String note) {
    this.note = note;
    }


    public static UnitOfWeight valueOf(Integer unit) {
    for (UnitOfWeight ofWeight : units) {
    if (unit == null) {
    return UNKNOWN;
    }
    if (ofWeight.match(unit)) {
    return ofWeight;
    }
    }
    return UNKNOWN;
    }


    /**
    * 获取对应枚举
    * @param unit
    * @return
    */
    public abstract boolean match(int unit);

    /**
    * 错误的值
    * @return
    */
    public boolean unknown() {
    return false;
    }


    public static void main(String[] args) {
    Integer unit = null;
    //getUnit (type2);
    UnitOfWeight ofWeight = UnitOfWeight.valueOf(unit);
    if (!ofWeight.unknown()) {
    String transferredUnit = ofWeight.getNote();
    /...
    }
    }
    }

    根据你 append 的代码用了一个枚举来做, 根据你的描述我想有几个点需要扩展,
    1. 从 pdf 解析 type 值;
    2. 有很多情况(可能因为历史原因很多地方使用了不同的值代表某一个单位);
    所以我建议使用枚举, 原因是:
    1. 我觉得后面随着业务需要或者其他原因重构, 可能慢慢的这些代表某一个单位的值会改变或者统一为一个,所以你需要修改 通过枚举可以统一在一处,便于修改;
    2. 再者也方便返回的字符值变更 总之对于变更这个枚举类基本上可以应对 90%以上的情况;
    3. match 方法可以做针对行的扩展和优化;
    boileryao
        44
    boileryao  
       2019-12-31 16:20:59 +08:00
    ```java
    // Put this map somewhere
    Map<Integer, String> codeMeaningInfo = new HashMap<>();
    codeMeaningInfo.put(1, "你好");
    codeMeaningInfo.put(2, "你好好");
    codeMeaningInfo.put(3, "你好好好");

    // Using this map
    String codeMeaning = codeMeaningInfo.get(code);
    ```
    一般情况下 Map 应该全局唯一,另外推荐 Kotlin 的 `when` 表达式。
    loryyang
        45
    loryyang  
       2019-12-31 16:22:23 +08:00
    可以的话,尽量不要用 null,容易在各种传递运算中出现空指针异常。比如你这个 code 和 codeMeaning,code=-1,codeMeaning=“”表示异常。甚至可以用 Enum 来包装这些内容
    如果硬是要用 null,我建议把 null 的处理和其他处理分开。尽量不要用三元表达式,这种东西比较反人类,写起来很爽,看起来一头包。
    你这种情况可以写个函数 getCodeMeaning(Integer code) {
    if (code == null) {
    return null;
    } else if (code == 1) {
    ******
    }
    代码在可读可维护性面前,简洁性可以要求低一些
    luozic
        46
    luozic  
       2019-12-31 16:45:26 +08:00
    如果 java 有 pattern match 就可以玩优雅;但是 Java 没有,所以,理智一点,用表驱动去糊弄算了。
    redford42
        47
    redford42  
       2019-12-31 17:24:29 +08:00
    前几天看到一个 java8 的 optional
    但其实我没看太明白...
    loryyang
        48
    loryyang  
       2019-12-31 17:27:32 +08:00
    @loryyang #45 另外还有一个避免魔法值,前面也好多人提了。对于这一点,我是觉得,你考虑一下是否有必要做。你这种 case,直接用一个 ImmutableMap 好了,这样可以变成:
    ImmutableMap.<Integer, String>builder().put(1, "").put(2, "").build()
    然后 getCodeMeaning 函数里面变成
    if (code == null) {
    return null;
    }
    if (code in immutableMap) {
    return immutableMap.get(code);
    }
    else {
    return ***;
    }

    回头看一下,还是 null 太多了,null 这东西还是不要在正常流程中出现吧
    nekoneko
        49
    nekoneko  
       2019-12-31 17:33:15 +08:00
    @redford42 #47 感觉 optional 就是婊子立牌坊
    godoway
        50
    godoway  
       2019-12-31 18:16:00 +08:00 via Android   1
    @nekoneko
    @redford42
    这其实是语法上提醒你检测空安全,例如有个接口入参 optional,你就知道这里可能为空,入参一个对象有可能你就忘了检测非空
    houOne
        51
    houOne  
       2019-12-31 18:37:57 +08:00
    你写的代码是给别人看的。 请你站在别人的角度思考一下,看到这个代码的心情
    itechify
        52
    itechify  
    PRO
       2019-12-31 19:25:42 +08:00 via Android
    @nekoneko 深层嵌套获取值,一直判断非空很嗦,Optional 可以解决这个问题
    winiex
        53
    winiex  
       2020-01-01 11:15:47 +08:00
    永远不要嵌套多层三元表达式,三元表达式当且仅当只有一层逻辑判断时才可以使用。其它情况一律用 if else 老实地写。我甚至连一层逻辑判断都想强制只能用 if else。
    brucefu
        54
    brucefu  
       2020-01-01 15:32:39 +08:00
    @micean 能让别人一秒就看懂的东西,就不要搞成两秒
    micean
        55
    micean  
       2020-01-01 16:49:23 +08:00
    @brucefu

    code == null ? null :
    code == 1 ? "你好" :
    code == 2 ? "你好好" :
    code == 3 ? "你好好好" :
    "其他";

    这不就是一个简易秒懂的 switch,楼上其他代码也做不到这么工整
    micean
        56
    micean  
       2020-01-01 16:55:50 +08:00
    另外嵌套的三元还可以轻轻松松给 final 修饰的赋值

    final String name =

    code == null ? "" :
    code == 1 ? "你好" :
    code == 2 ? "你好好" :
    code == 3 ? "你好好好" :
    "其他";
    secondwtq
        57
    secondwtq  
       2020-01-01 18:31:04 +08:00
    这不就是一个 Maybe Integer 解决的问题 ... 搞这么复杂
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3469 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 04:57 PVG 12:57 LAX 21:57 JFK 00:57
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86