• 请不要在回答技术问题时复制粘贴 AI 生成的内容
sandman511
V2EX  ›  程序员

Java :如何处理空指针?

  •  1
     
  •   sandman511 · Dec 31, 2019 · 7442 views
    This topic created in 2500 days ago, the information mentioned may be changed or developed.
    Integer code = getCode();
    String codeMeaning = code == null ? null :
                        code == 1 ? "你好" :
                        code == 2 ? "你好好" :
                        code == 3 ? "你好好好";
    

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

    Supplement 1  ·  Dec 31, 2019

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

    Supplement 2  ·  Dec 31, 2019

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

    //方法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应该是比较好的方法

    Supplement 3  ·  Dec 31, 2019

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

    57 replies  •  2020-01-01 18:31:04 +08:00
    avk458
    avk458
    Dec 31, 2019
    1
    三元表达式还能这样玩儿?
    按照这个`codeMeaning`的意思来用 switch 是不是更好?
    包装类比较是不是应该用 equals ?
    pmispig
    pmispig
    Dec 31, 2019❤️7
    2
    谁写的,先把他头锤爆
    ezrealinxh
    ezrealinxh
    Dec 31, 2019
    3
    // TODO: Bullshit
    sandman511
    sandman511
    OP
    Dec 31, 2019
    4
    @pmispig 实不相瞒。。我写的。。
    manami
    manami
    Dec 31, 2019 via Android
    5
    Objects.equals(a, b)
    optional
    optional
    Dec 31, 2019❤️1
    6
    // 第一种提前返回
    ```
    if (Objects.isNull(code)) {
    return null;
    }
    //switch or if
    ```
    //第二种,
    ```
    Optional.ofNullable(code).map(code->{
    //switch or if
    }).orElse(null);
    ```
    passerbytiny
    passerbytiny
    Dec 31, 2019
    7
    一,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
    sandman511
    OP
    Dec 31, 2019
    8
    @avk458 我嫌 switch 写起来太麻烦了 这个逻辑比较简单 就三行 所以用了三元。。。请教一下三元不能这样用吗?
    确实该用 equals,但是 code 可能为 null,equals 可能抛空指针。。所以不知道该咋办了
    lff0305
    lff0305
    Dec 31, 2019❤️2
    9
    ```
    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
    lovelive1024
    Dec 31, 2019
    10
    Map<Integer, String> map = new ....
    codeMeaning = map.get(code);
    U7Q5tLAex2FI0o0g
    U7Q5tLAex2FI0o0g
    Dec 31, 2019
    11
    实不相瞒,三元这么嵌套不加括号的,除了傻逼笔试题外,工作中这样写的同事我会打死他(不是不能嵌套,你得加括号增加可读性)
    lihongjie0209
    lihongjie0209
    Dec 31, 2019
    12
    不加括号就是作死
    w292614191
    w292614191
    Dec 31, 2019
    13
    我感觉比楼上那些 if else switch 好看多了。

    都是些秀无意义代码的。

    你看看 7、9 楼,

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

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

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

    你的 getUnit(type) 应该直接返回这个 unit class。
    palmers
    palmers
    Dec 31, 2019❤️1
    43
    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
    boileryao
    Dec 31, 2019
    44
    ```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
    loryyang
    Dec 31, 2019
    45
    可以的话,尽量不要用 null,容易在各种传递运算中出现空指针异常。比如你这个 code 和 codeMeaning,code=-1,codeMeaning=“”表示异常。甚至可以用 Enum 来包装这些内容
    如果硬是要用 null,我建议把 null 的处理和其他处理分开。尽量不要用三元表达式,这种东西比较反人类,写起来很爽,看起来一头包。
    你这种情况可以写个函数 getCodeMeaning(Integer code) {
    if (code == null) {
    return null;
    } else if (code == 1) {
    ******
    }
    代码在可读可维护性面前,简洁性可以要求低一些
    luozic
    luozic
    Dec 31, 2019
    46
    如果 java 有 pattern match 就可以玩优雅;但是 Java 没有,所以,理智一点,用表驱动去糊弄算了。
    redford42
    redford42
    Dec 31, 2019
    47
    前几天看到一个 java8 的 optional
    但其实我没看太明白...
    loryyang
    loryyang
    Dec 31, 2019
    48
    @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
    nekoneko
    Dec 31, 2019
    49
    @redford42 #47 感觉 optional 就是婊子立牌坊
    godoway
    godoway
    Dec 31, 2019 via Android❤️1
    50
    @nekoneko
    @redford42
    这其实是语法上提醒你检测空安全,例如有个接口入参 optional,你就知道这里可能为空,入参一个对象有可能你就忘了检测非空
    houOne
    houOne
    Dec 31, 2019
    51
    你写的代码是给别人看的。 请你站在别人的角度思考一下,看到这个代码的心情
    itechify
    itechify
    Dec 31, 2019 via Android
    52
    @nekoneko 深层嵌套获取值,一直判断非空很啰嗦,Optional 可以解决这个问题
    winiex
    winiex
    Jan 1, 2020
    53
    永远不要嵌套多层三元表达式,三元表达式当且仅当只有一层逻辑判断时才可以使用。其它情况一律用 if else 老实地写。我甚至连一层逻辑判断都想强制只能用 if else。
    brucefu
    brucefu
    Jan 1, 2020
    54
    @micean 能让别人一秒就看懂的东西,就不要搞成两秒
    micean
    micean
    Jan 1, 2020
    55
    @brucefu

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

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

    final String name =

    code == null ? "" :
    code == 1 ? "你好" :
    code == 2 ? "你好好" :
    code == 3 ? "你好好好" :
    "其他";
    secondwtq
    secondwtq
    Jan 1, 2020
    57
    这不就是一个 Maybe Integer 解决的问题 ... 搞这么复杂
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   4868 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 191ms · UTC 06:57 · PVG 14:57 · LAX 22:57 · JFK 01:57
    ♥ Do have faith in what you're doing.