解决“三元运算符”中i++和++i不一致问题

前言

我们都知道i++和++i两个的赋值方式不一样,i++是先赋值在累加,++i是先累加在赋值。

问题发现

在业务代码编写的过程中,为了使代码简洁,使用三元运算符进行选择后累加,代码如下所示:

public class Test {
    public static void main(String[] args) {
        Integer i = 0;
        i = i == null ? 1 : i++;
        System.out.println(i);
        
    }
}

执行后,你会发现结果为0,并没有进行所谓的累加,为此进行深入探讨。

问题解决

下面通过a++和++b对比来进行讲解

public class Test {
    public static void main(String[] args) {
        Integer a = 0;
        a++;
        System.out.println(a);
        Integer b = 0;
        ++b;
        System.out.println(b);
        /** Output:
         *  1
         *  1
         */
    }
}

编译后:

public class Test {
    public Test() {
    }

    public static void main(String[] var0) {
        Integer var1 = 0;
        var1 = var1 + 1;
        System.out.println(var1);
        Integer var2 = 0;
        var2 = var2 + 1;
        System.out.println(var2);
    }
}

我们先通过简单的a++和++b,通过编译后的字节码文件,可以看到,两个都进行了加1赋值,可以看到最后的结果输出都是1。

我们换种方式如果直接打印a++和++b,结果会如何:

public class Test {
    public static void main(String[] args) {
        Integer a = 0;
        System.out.println(a++);
        Integer b = 0;
        System.out.println(++b);
        /** Output:
         *  0
         *  1
         */
    }
}

编译后

public class Test {
    public Test() {
    }

    public static void main(String[] var0) {
        Integer var1 = 0;
        PrintStream var10000 = System.out;
        var1 + 1;
        var10000.println(var1);
        Integer var2 = 0;
        System.out.println(var2 + 1);
    }
}

很显然a++在字节码文件中,加1后并未赋值,这也就得知a++的结果为0;而++b你会发现,始终保持加1状态,所以结果为1。

回归正题,在“三元运算符”中,a++和++b执行原理又会如何呢?

public class Test {
    public static void main(String[] args) {
        Integer a = 0;
        a = a == null ? 1 : a++;
        System.out.println(a);
        Integer b = 0;
        b = b == null ? 1 : ++b;
        System.out.println(b);
        /** Output:
         *  0
         *  1
         */
    }
}

编译后:

public class Test {
    public Test() {
    }

    public static void main(String[] var0) {
        Integer var1 = 0;
        int var10000;
        if (var1 == null) {
            var10000 = 1;
        } else {
            var1 + 1;
            var10000 = var1;
        }

        var1 = var10000;
        System.out.println(var1);
        Integer var2 = 0;
        var2 = var2 == null ? 1 : Integer.valueOf(var2 + 1);
        System.out.println(var2);
    }
}

我们通过字节码文件可以看到,a++的“三元运算符”被拆分成了if else语句,将值赋给新的变量,a++在执行加1后并未赋值,这也就导致最终赋值给变量的值为0;++b和预期一样加1,只不过“三元运算符”中不能直接进行累加操作,所以通过valueOf()给他进行了包裹。

我们再来看下正常的if else语句中,a++是一个怎样的执行过程:

public class Test {
    public static void main(String[] args) {
        Integer a = 0;
        if(a == null){
            a =1;
        }else{
            a++;
        }
        System.out.println(a);
        /** Output:
         *  1
         */
    }
}

编译后

public class Test {
    public Test() {
    }

    public static void main(String[] var0) {
        Integer var1 = 0;
        if (var1 == null) {
            var1 = 1;
        } else {
            var1 = var1 + 1;
        }

        System.out.println(var1);
    }
}

可以看到直接进行加1操作,最终结果为1。

最后我们再来讲解,循环体中的a++是如果执行的:

public class Test {
    public static void main(String[] args) {
        Integer a = 0;
        for (int i = 0; i < 5; i++) {
            a = a++;
            System.out.print(a);
        }
        System.out.println();
        for (int i = 0; i < 5; i++) {
            System.out.print(a++);
        }
        /** Output:
         *  00000
         *  01234
         */
    }
}

编译后

public class Test {
    public Test() {
    }

    public static void main(String[] var0) {
        Integer var1 = 0;

        int var2;
        Integer var3;
        for(var2 = 0; var2 < 5; ++var2) {
            var3 = var1;
            var1 + 1;
            var1 = var1;
            System.out.print(var3);
        }

        System.out.println();

        for(var2 = 0; var2 < 5; ++var2) {
            PrintStream var10000 = System.out;
            var3 = var1;
            var1 = var1 + 1;
            var10000.print(var3);
        }

    }
}

第一个循环体,定义一个新变量赋值后,进行加1并没赋值,所以每次遍历输出的结果都一样,当然没有人会在累加1操作后再重新赋值,这会是一个bug,要注意。第二个循环体就很清楚了,先赋值后累加,所以输出的结果为:01234。

总结

通过前面讲解的例子,我们发现i++是先赋值在累加,++i是先累加在赋值,这种说法不一定完全正确,或者说i++这种说法得分情况来说。++i我们就不进行过多的总结了,得到的结果总会先加1。下面我们把之前i++的例子归纳一下:

为什么i++累加后未赋值?

前面讲解的例子中发现字节码文件中加1未赋值的情况,这种情况应该分两种,一种是正常情况下的累加,另一种是“三元运算符”的累加。

  1. 先来讲解正常情况下的累加
public class Test {
    public static void main(String[] args) {
        Integer a = 0;
        System.out.println(a++);

        Integer b = 0;
        System.out.println(b++);
        b++;
        System.out.println(b);
        /** Output:
         *  0
         *  0
         *  2
         */
    }
}

编译后

public class Test {
    public Test() {
    }

    public static void main(String[] var0) {
        Integer var1 = 0;
        PrintStream var10000 = System.out;
        var1 + 1;
        var10000.println(var1);
        Integer var2 = 0;
        var10000 = System.out;
        Integer var3 = var2;
        var2 = var2 + 1;
        var10000.println(var3);
        var2 = var2 + 1;
        System.out.println(var2);
    }
}

编译后,我们看到第一种情况没有在进行赋值,所以结果为0;第二种情况可以看到累加的时候赋值了,而且是先赋值后累加的。总结:累加时是否需要赋值,是取决于接下来是否还需要对这个值进行操作,并不代表没有进行累加。

  1. 再来讲解“三元运算符”的累加
public class Test {
    public static void main(String[] args) {
        Integer a = 0;
        a = a == null ? 1 : a++;
        System.out.println(a);
        a++;
        System.out.println(a);
        /** Output:
         *  0
         *  1
         */
    }
}

编译后

public class Test {
    public Test() {
    }

    public static void main(String[] var0) {
        Integer var1 = 0;
        int var10000;
        if (var1 == null) {
            var10000 = 1;
        } else {
            var1 + 1;
            var10000 = var1;
        }

        var1 = var10000;
        System.out.println(var1);
        var1 = var1 + 1;
        System.out.println(var1);
    }
}

与正常累加有所不同,后面累加对这个值的操作,丝毫不影响“三元运算符”操作。通过字节码文件,我们发现赋值时,将值赋给var10000变量,但是此过程中累加时并未赋值操作,然后再去通过var10000赋值给var1 变量得到最终结果,所以导致此结果为0,再来看一段代码(如下)

public class Test {
    public static void main(String[] args) {
        Integer a = 0;
        if (a == null) {
            a = 1;
        } else {
            System.out.println(a++);
        }
        /** Output:
         *  0
         */
    }
}

编译后

public class Test {
    public Test() {
    }

    public static void main(String[] var0) {
        Integer var1 = 0;
        if (var1 == null) {
            var1 = 1;
        } else {
            PrintStream var10000 = System.out;
            var1 + 1;
            var10000.println(var1);
        }

    }
}

通过上面这段代码我想答案已经出来了,为什么没有赋值?因为再“三元运算符”中或者上面这段代码中,a++之后并没有再做任何操作,“三元运算符”代码后的累加操作,不属于此代码块的生命周期内。所以并未赋值,结果为0。再没有了解原理之前,你可能会说,因为a++是先累加后赋值,这样说法没错,但只说对一半。

为什么i++不一定是先赋值再累加?

看过前面的案例你就清楚了,很简单,这取决于你累加后是否还会有操作,以循环体为例,再来进行讲解:

public class Test {
    public static void main(String[] args) {
        Integer a = 0;
        for (int i = 0; i < 5; i++) {
            a++;
            System.out.print(a);
        }
        System.out.println();
        Integer b = 0;
        for (int i = 0; i < 5; i++) {
            System.out.print(b++);
        }
        /** Output: 
         *  12345
         *  01234
         */
    }
}

编译后

public class Test {
    public Test() {
    }

    public static void main(String[] var0) {
        Integer var1 = 0;

        for(int var2 = 0; var2 < 5; ++var2) {
            var1 = var1 + 1;
            System.out.print(var1);
        }

        System.out.println();
        Integer var6 = 0;

        for(int var3 = 0; var3 < 5; ++var3) {
            PrintStream var10000 = System.out;
            Integer var4 = var6;
            var6 = var6 + 1;
            var10000.print(var4);
        }

    }
}

通过字节码代码,你会发现如果累加后还有操作,哪结果就会先累加再赋值,所以第一个循环体结果为12345;如果后面没有操作了就是先赋值再累加,第二个循环体结果为01234。

经过这么些个案例讲解,希望能解决你疑惑,给你带来收获,欢迎交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值