← [ BACK_TO_NOTES ]

Java 运算符与表达式

Java 运算符、优先级、结合性、短路求值与数值提升:表达式如何得到类型化的值。

#concept #growing #dev #java

[!info] related notes

Java 运算符与表达式

这个概念为什么出现

控制流、校验与计算都建立在表达式上。若优先级、短路与数值提升不清楚,会出现:

  • a + b + "x" 拼接顺序意外
  • && 与 & 混用导致空指针
  • byte 运算后无法直接赋回 byte

[!abstract] 一句话理解 表达式在类型规则下求值;算术有提升与溢出,布尔逻辑常用短路运算符,优先级可用括号显式化,对象相等比较要区分引用 == 与业务 equals。

最小可运行示例

先把示例放进业务场景,再看代码:

场景:促销服务判断能否下单并计算计费件数

规则:在售、下单量为正且库存足够才可售;每满三件,其中一件免费。计费函数接收非负总件数。 教学点:短路、比较、算术、括号。

public class ShippingRule {
    // canFulfill:判断库存是否够扣。
    //
    // 业务意图:缺货或已下架时不能下单。
    // 教学点:&& 短路——左侧 false 时不评估右侧。
    static boolean canFulfill(boolean onShelf, int stock, int want) {
        // 若 onShelf 为 false,不会执行 stock >= want(本例无副作用,但模式重要)。
        return onShelf && want > 0 && stock >= want;
    }

    // billableUnits:总件数中每满三件免一件;不额外增加赠品。
    static int billableUnits(int want) {
        if (want < 0) throw new IllegalArgumentException("want");
        // 整数除法截断:免费件数按组计算。
        int giftGroups = want / 3;
        return want - giftGroups;
    }

    public static void main(String[] args) {
        System.out.println(canFulfill(true, 10, 3));  // true
        System.out.println(canFulfill(false, 10, 3)); // false
        System.out.println(billableUnits(4));         // 4 - 1 = 3

        String sku = "SKU";
        // + 左结合:先 1+2 得 3,再和字符串拼接。
        System.out.println(1 + 2 + sku); // 3SKU
        // 先字符串拼接再加:12SKU
        System.out.println("" + 1 + 2 + sku);
    }
}

建议运行:

javac ShippingRule.java && java ShippingRule

期望输出:

true
false
3
3SKU
12SKU

结合场景再看三个关注点

  1. 短路保护:obj != null && obj.isActive() 是惯用防 NPE 模式。
  2. 整数除法会吞小数,促销/均分要显式策略。
  3. 字符串 + 改变后续运算的类型与顺序,日志拼接要清醒。

核心概念与准确模型

1. 常用类别

类别例子注意
算术+ - * / %整数除法向零截断;整数加减乘溢出环绕,浮点另有规则
复合赋值+= *=隐含转换规则
比较== != < >基本类型比值;引用比引用
逻辑短路&& ||可能跳过右操作数
逻辑非短路& |(布尔时)左侧正常完成后仍计算右侧,不按布尔结果短路
三元c ? a : b两端类型需兼容
位运算& | ^ ~ << >> >>>协议/标志位
instanceofx instanceof Type模式匹配形态随版本增强

2. 数值提升(直觉)

  • 小于 int 的类型在许多算术中提升到 int
  • int 与 long 混合 → long
  • 浮点参与 → 向浮点提升

3. 优先级

不要靠背诵全表写业务:

  • 乘除优先于加减
  • 比较优先于逻辑与
  • 不确定就加括号,给读者看意图。优先级决定分组;Java 操作数求值遵循从左到右,不能据优先级推断副作用发生顺序。

4. == 对引用

  • 比较是否同一对象引用(或同一基本值)
  • 字符串内容比较用 equals(并注意 null 安全)
  • 详解见 equals 与 hashCode

边界情况与反直觉行为

  1. 整数 % 是余数:非零结果与被除数同号,如 -5 % 2 == -1;需要向下取整对应的模运算可考虑 Math.floorMod。
  2. >>> 无符号右移 与 >> 算术右移不同。
  3. 浮点 == 有精确定义:NaN 不等于任何值(含自身),正负零相等;近似计算是否使用容差,要按业务误差模型决定。
  4. 自增作表达式 i++ vs ++i 的值不同。

常见误区

[!warning] 常见误区:用 & 做空安全判断 错误理解:obj != null & obj.flag 一样安全。
正确模型:& 两侧都求值,仍可能 NPE;用 &&。
为何易错:位运算与逻辑运算符号重叠。

工程实践

  1. 复杂条件拆成命名布尔局部变量。
  2. 金额/比例计算写单测。
  3. 位运算集中在基础设施编解码,不散落业务。
  4. 日志优先 format 或日志框架参数化,减少 + 迷雾。

本节总结

  • 表达式 = 运算符 + 操作数 + 类型规则
  • 短路、提升、优先级是三条主线
  • 括号与命名条件提升可维护性

自测题

  1. 为何 onShelf && stock>=want 比先算库存再与更合适(当右式昂贵或有副作用时)?
  2. byte a=1; byte b=2; byte c=a+b; 为何常需强转?
参考答案
  1. 短路可跳过昂贵/不安全的右操作数。
  2. a+b 提升为 int,赋回 byte 要显式转换。

延伸阅读与资料来源

资料类型支撑内容
JLS Expressions规范表达式与运算符
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本