2. 问题引入

boolean 是 Java 的基本数据类型之一,只有两个值:truefalse。本文要解决的问题很简单:**给定三个布尔值,判断其中至少有两个为 true**。

虽然问题本身不难,但我们将探索几种优雅的解决方案,并分析每种方法是否易于扩展为更通用的场景:**给定 n 个布尔值,判断其中至少 x 个为 true**。

为验证各方案,我们先用 Map 存储测试用例和预期结果:

static final Map<boolean[], Boolean> TEST_CASES_AND_EXPECTED = Map.of(
    new boolean[]{true, true, true}, true,
    new boolean[]{true, true, false}, true,
    new boolean[]{true, false, false}, false,
    new boolean[]{false, false, false}, false
);

说明:这里使用 Java 9+ 的 Map.of 创建不可变 Map。若使用 Java 8,可改用 Guava 的 ImmutableMap

接下来,我们逐步分析解决方案。

3. 遍历布尔值

最直接的思路是遍历三个布尔值并统计 true 的个数。一旦计数器 ≥ 2 就立即返回 true,否则最终返回 false

public static boolean twoOrMoreAreTrueByLoop(boolean a, boolean b, boolean c) {
    int count = 0;
    for (boolean i : new Boolean[] { a, b, c }) {
        count += i ? 1 : 0;
        if (count >= 2) {
            return true;
        }
    }
    return false;
}

测试验证:

TEST_CASES_AND_EXPECTED.forEach((array, expected) -> 
    assertThat(ThreeBooleans.twoOrMoreAreTrueByLoop(array[0], array[1], array[2])).isEqualTo(expected)
);

优势:逻辑清晰,且易于扩展为通用方案(接受布尔数组和阈值 x):

public static boolean xOrMoreAreTrueByLoop(boolean[] booleans, int x) {
    int count = 0;
    for (boolean i : booleans) { 
        count += i ? 1 : 0;
        if (count >= x) {
            return true;
        }
    }
    return false;
}

4. 转换为数值计算

另一种思路是将布尔值转换为整数后求和,判断结果是否 ≥ 2:

public static boolean twoOrMoreAreTrueBySum(boolean a, boolean b, boolean c) {
    return (a ? 1 : 0) + (b ? 1 : 0) + (c ? 1 : 0) >= 2;
}

测试验证:

TEST_CASES_AND_EXPECTED.forEach((array, expected) -> 
    assertThat(ThreeBooleans.twoOrMoreAreTrueBySum(array[0], array[1], array[2])).isEqualTo(expected)
);

同样可扩展为通用方案,使用 Stream API 实现更简洁:

public static boolean xOrMoreAreTrueBySum(Boolean[] booleans, int x) {
    return Arrays.stream(booleans)
        .mapToInt(b -> Boolean.TRUE.equals(b) ? 1 : 0)
        .sum() >= x;
}

注意:参数类型为 Boolean[] 而非 boolean[],因为 Stream 不支持基本类型数组。

5. 使用逻辑运算符

通过逻辑与(&&)运算组合所有两两布尔对,只要有一对为 true 即满足条件:

public static boolean twoOrMoreAreTrueByOperators(boolean a, boolean b, boolean c) {
    return (a && b) || (a && c) || (b && c);
}

测试验证:

TEST_CASES_AND_EXPECTED.forEach((array, expected) -> 
    assertThat(ThreeBooleans.twoOrMoreAreTrueByOperators(array[0], array[1], array[2])).isEqualTo(expected)
);

局限性

  • 仅适用于判断至少两个 true 的场景
  • 当布尔值数量 n 增大时,需要构造极长的逻辑表达式链
  • 无法扩展为通用方案

6. 使用卡诺图

卡诺图(Karnaugh Map)是简化布尔代数表达式的经典工具。针对三个布尔值 A、B、C,构建卡诺图:

      | C | !C
------|---|----
 A  B | 1 | 1 
 A !B | 1 | 0
!A !B | 0 | 0
!A  B | 1 | 0

解读

  • 1 表示至少两个 true 的情况
  • 按行/列分组简化表达式:
    • 第一行(A、B 均为 true):A && B
    • 第一列(C 为 true 且 A/B 至少一个 true):C && (A || B)

最终表达式为:

public static boolean twoOrMoreAreTrueByKarnaughMap(boolean a, boolean b, boolean c) {
    return (c && (a || b)) || (a && b);
}

测试验证:

TEST_CASES_AND_EXPECTED.forEach((array, expected) -> 
    assertThat(ThreeBooleans.twoOrMoreAreTrueByKarnaughMap(array[0], array[1], array[2])).isEqualTo(expected)
);

局限性

  • 当布尔值数量 n 增大时,构建卡诺图复杂度急剧上升
  • 不适合动态通用场景

7. 使用异或运算符

利用异或(^)的特性设计巧妙解法:

  • a ^ btrue,说明 a、b 值不同,此时结果取决于 c
  • a ^ bfalse,说明 a、b 值相同,此时结果取决于 a
public static boolean twoOrMoreAreTrueByXor(boolean a, boolean b, boolean c) {
    return a ^ b ? c : a;
}

测试验证:

TEST_CASES_AND_EXPECTED.forEach((array, expected) -> 
    assertThat(ThreeBooleans.twoOrMoreAreTrueByXor(array[0], array[1], array[2])).isEqualTo(expected)
);

特点

  • 代码极简,但理解门槛较高
  • 仅适用于三个布尔值且判断至少两个 true 的固定场景
  • 无法扩展为通用方案

8. 总结

我们分析了五种判断三个布尔值中至少两个为 true 的方案:

方案 可扩展性 适用场景
遍历统计 ⭐⭐⭐⭐⭐ 通用场景(n 个布尔值,x 个阈值)
数值求和 ⭐⭐⭐⭐ 通用场景
逻辑运算符 仅固定三个布尔值
卡诺图 仅固定三个布尔值
异或运算 仅固定三个布尔值

推荐选择

  • 需要通用性 → 遍历统计数值求和
  • 仅处理三个布尔值 → 异或运算(代码最简)或 逻辑运算符(可读性更佳)

踩坑提醒:卡诺图和异或方案虽然巧妙,但扩展性差,实际开发中除非有特殊需求,否则不建议使用。


原始标题:Check if at Least Two Out of Three Booleans Are True in Java | Baeldung