在写 Java 异常处理代码时,你可能见过这样的写法:

try {
    // 可能抛出多种异常
} catch (IOException | SQLException e) {
    e.printStackTrace();
}

这里用的是单个竖线 |,而不是我们更熟悉的逻辑或 ||
那么问题来了:为什么不能写成 catch (IOException || SQLException e) 呢?

很多人第一次看到这语法时都会下意识地觉得奇怪。下面我们来一步步搞清楚这个问题。


一、| 在多异常捕获中的真正含义

在 Java 7 之后,语言引入了“多异常捕获(multi-catch)”语法。
它允许我们用一个 catch 同时捕获多个不同类型的异常,语法是:

catch (异常类型1 | 异常类型2 | ... 变量名)

例如:

try {
    readFromFile();
    connectToDatabase();
} catch (IOException | SQLException e) {
    System.err.println("发生异常:" + e.getMessage());
}

这行代码的意思是:

如果 try 块中抛出了 IOExceptionSQLException,都由这个 catch 块处理。

注意:
这里的 | 不是逻辑“或”,而是 类型联合符号(Type Union Operator)
换句话说,它表示“这个异常变量 e 的类型可能是 A,也可能是 B”。


二、为什么不能用 ||

|| 是逻辑运算符,只能用于 boolean 表达式
比如:

if (a > 0 || b < 10) {
    System.out.println("条件成立");
}

它的作用是对两个布尔结果做“逻辑或”,并且有短路特性(左边为 true 时右边不再计算)。

但在 catch 中,IOExceptionSQLException类型(Type),不是布尔表达式。
所以写成 catch (IOException || SQLException e) 时,编译器会直接报错:

error: bad operand types for binary operator '||'

这就好比你在问编译器:“IOException 是 true 还是 false?”
显然,这没有任何意义。


三、编译器背后的处理方式

其实下面两种写法在逻辑上是等价的:

catch (IOException | SQLException e) {
    e.printStackTrace();
}

catch (IOException e) {
    e.printStackTrace();
} catch (SQLException e) {
    e.printStackTrace();
}

只是 Java 提供了更简洁的语法糖,让我们不用重复写多段 catch。

编译器在编译时,会把 | 理解为“这几个类型的并集”,并自动生成对应的异常匹配逻辑。


四、||| 的区别总结

对比项|||
用途类型联合(multi-catch)、按位或 | 、逻辑或(布尔表达式)逻辑或(布尔表达式)
是否短路
操作对象类型或数值或BooleanBoolean
是否能用在 catch可以不行

五、一个小例子对比一下

try {
    if (Math.random() > 0.5) {
        throw new IOException("文件出错");
    } else {
        throw new SQLException("数据库异常");
    }
} catch (IOException | SQLException e) {
    System.out.println("捕获到异常:" + e.getMessage());
}

运行结果可能输出:

捕获到异常:文件出错

或:

捕获到异常:数据库异常

无论是哪一种异常,程序都能被正确捕获并处理。
而如果你尝试写成 catch (IOException || SQLException e),编译都不会通过。


六、延伸阅读:||| 到底是什么关系?

有些同学可能会疑惑:
我查资料时明明看到很多地方说——

| 是逻辑或,|| 是短路或”。

这和上面的解释矛盾吗?
其实不矛盾,只是说的语境不同

Notes:什么是短路或(||

短路或是 Java 中的一种逻辑运算方式。

当使用 || 时,程序会从左到右计算两个布尔表达式:

  • 如果左边表达式为 true,右边的表达式不会再执行,整个结果直接是 true

  • 只有当左边为 false 时,才会去计算右边。

这就是所谓的 “短路” —— 遇到能确定结果的情况就“提前结束”运算。而 | 判断的是所有的条件。

1. 在布尔表达式中

当操作数是 boolean 时,| 也可以作为逻辑或使用,只不过它不会短路。

boolean a = true;
boolean b = false;

System.out.println(a | b);   // true(逻辑或,不短路)
System.out.println(a || b);  // true(逻辑或,短路)

所以,“| 是逻辑或、|| 是短路或”在布尔表达式中是正确的


2. 在整数表达式中

当操作数是整数时,| 表示 按位或

int x = 5;  // 0101
int y = 3;  // 0011
System.out.println(x | y);  // 输出 7(二进制 0111)

3. 在异常捕获中

而在 catch (IOException | SQLException e) 里,
这个 | 已经不是运算符,而是类型联合符号
它的作用是告诉编译器:

这个 catch 块可以同时处理多种异常类型。

也就是说:

  • 表达式中的 |运算符

  • 多异常捕获中的 |语法符号


4. 再顺带提一下 &&&

同理:

符号语义是否短路
&按位与 / 逻辑与(非短路)
&&逻辑与(短路)

它们与 ||| 的关系是完全对称的。


七、总结

  • 在多异常捕获中,| 表示类型联合,不是逻辑运算符;

  • || 是逻辑“或”运算符,只能用于布尔值;

  • | 是逻辑或,|| 是短路或” 的说法只在布尔表达式语境下成立;

  • 同理,&&& 的关系也一样。

💡 一句话记忆:

| 是“多面手”:可以是按位或、非短路逻辑或、或类型联合;
|| 只做一件事——短路逻辑或


这类语法点虽然不复杂,但理解背后的“语境差异”很重要。
掌握这些细节,不仅能让代码更优雅,也能让我们的 Java 基础更加扎实。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐