
赋值运算符不是语法糖,是隐式类型转换的开关
Java里 +=、-= 这类复合赋值运算符,表面看只是省两个字符,实际会触发隐式强制转换。比如 short s = 1; s += 1; 能编译通过,但 s = s + 1; 直接报错:「possible loss of precision」。因为 s + 1 结果是 int,而 short 不能直接接收 int 值;但 += 编译器会自动补上 (short) 强转。
- 只对基本数值类型(
byte、short、char)有明显效果,int及以上类型行为一致,没差别 -
String的+=是特例:底层调用StringBuilder.append(),不是简单拼接,但要注意在循环里滥用会生成大量临时对象 - 自定义类型不支持重载这些运算符,别指望
myList += item能工作
在循环里用 += 累加数字?先看数据量和类型
小数据量时写 sum += value; 没问题,但若 value 是 double,且循环上万次,浮点误差会累积。更糟的是,如果 sum 是 float,而 value 是 double,+= 会悄悄截断精度——编译器不会警告,运行结果却偏了。
- 金融计算必须用
BigDecimal,+=对它无效,别硬套 - 整数累加超过
Integer.MAX_VALUE?+=不会报错,只会静默溢出,建议改用long或检查Math.addExact() - 循环体里有异常可能中断累加,
+=本身不带原子性,多线程场景必须加锁或换AtomicInteger.addAndGet()
+= 和 = 在字符串拼接中的性能分水岭
写 str += "a"; 看似简洁,但每次执行都会新建 StringBuilder、append、toString,开销远大于显式复用一个 StringBuilder。JVM 8+ 对方法内单行字符串拼接做了优化,但仅限于编译期可确定的字面量,比如 str = "a" + "b" + "c";;一旦涉及变量,优化就失效。
- 循环内拼接:必须用
StringBuilder,+=是反模式 - 方法参数拼接如
log("id=" + id + ", name=" + name),建议改用占位符(如 SLF4J 的log.info("id={}, name={}", id, name)),避免无谓构造 -
String不可变,+=每次都生成新对象,GC 压力肉眼可见,尤其在高频日志或模板渲染中
链式赋值在 Java 中根本不存在
别被 Python 或 JavaScript 误导。Java 不支持 a = b = c = 0; 这种写法。你写的 int a, b, c; a = b = c = 0; 会编译失败,报错 incompatible types: int cannot be converted to boolean——因为 b = c = 0 被解析为 b = (c = 0),而 c = 0 返回 int,无法赋给 b(除非 b 是 int,但前面没声明类型)。最简写法仍是分开赋值或用数组初始化。
立即学习“Java免费学习笔记(深入)”;
- 想一行初始化多个同类型变量?只能写
int a = 0, b = 0, c = 0;,这是声明+赋值,不是链式赋值 - 对象引用可以「看起来」链式:
List<string> a = b = new ArrayList();</string>,但这是危险操作——a和b指向同一实例,后续修改互相影响 - IDE 自动补全有时会诱导你写
a = b = c;,务必删掉中间的=,否则编译不过
真正容易被忽略的,是复合赋值运算符在泛型和自动拆箱场景下的行为差异。比如 Integer i = 1; i += 1L; 会触发拆箱→加法→装箱,过程中若 i 是 null,直接抛 NullPointerException,连 += 的语法糖都救不了。











