Format Multiple ‘or’ Conditions in an If Statement in Java – 在 Java 的 If 语句中格式化多个 ‘or’ 条件

最后修改: 2023年 8月 30日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

While using an if statement, we might need multiple conditions in it with logical operators such as AND or OR. This may not be a clean design and affects the code’s readability and cognitive complexity.

在使用 if 语句时,我们可能需要在 逻辑操作符(如 AND 或 OR)中使用多个条件。这可能不是一个简洁的设计,会影响代码的可读性和认知复杂性

In this tutorial, we’ll see the alternatives to format multiple value conditions in an if statement.

在本教程中,我们将看到在 if 语句中格式化多值条件的替代方法。

2. Can We Avoid If Statements?

2.我们能否避免 If 语句?

Suppose we have an e-commerce platform and set up a discount for people born in specific months. Let’s have a look at a code snippet:

假设我们有一个电子商务平台,并为特定月份出生的人设置了折扣。让我们来看一段代码:

if (month == 10 || month == 11) {
    // doSomething()
} else if(month == 4 || month == 5) {
    // doSomething2()
} else {
    // doSomething3()
}

This might lead to some code that is difficult to read. Also, even if we have good test coverage, the code may be hard to maintain as it forces us, for example, to put together what different conditions are to execute a specific action.

这可能会导致一些代码难以阅读。此外,即使我们的测试覆盖率很高,代码也可能难以维护,因为它迫使我们,例如,将执行特定操作的不同条件放在一起。

2.1. Use Clean Code

2.1.使用简洁代码

We can apply patterns to replace many if statements. For example, we can move the logic of an if’s multiple conditions into a class or an Enum. At runtime, we’ll switch between interfaces based on the client input. Similarly, we can have a look at the Strategy pattern.

我们可以应用模式来替换许多 if 语句。例如,我们可以将 if 的多个条件的逻辑移到一个类或一个枚举中。在运行时,我们将根据客户端的输入在接口之间进行切换。同样,我们也可以参考 Strategy 模式

This does not strictly relate to formatting and usually leads to rethinking the logic. Nonetheless, it is something we can consider to improve our design.

这与格式没有严格的关系,通常会导致对逻辑的重新思考。不过,这也是我们改进设计时可以考虑的问题。

2.2. Improve Methods Syntax

2.2.改进方法语法

However, there is nothing wrong with using the if / else logic as long as the code is readable and easy to maintain. For example, let’s consider this code snippet:

不过,只要代码可读且易于维护,使用 if / else 逻辑并无不妥。例如,让我们来看看以下代码片段:

if (month == 8 || month == 9) {
    return doSomething();
} else {
    return doSomethingElse();
}

As a first step, we can avoid using the else part:

首先,我们可以避免使用 else 部分:

if (month == 8 || month == 9) {
    return doSomething();
}

return doSomethingElse();

Also, some other code can be improved, for example, by replacing month numbers with Enum of java.time package:

此外,还可以改进其他一些代码,例如用 java.time 包中的 Enum 代替月份数字:

if (month == OCTOBER || month == NOVEMBER || month == DECEMBER) {
    return doSomething();
}
// ...

These are simple yet effective code improvements. So, before applying complex patterns, we first should see if we can ease the code readability.

这些都是简单而有效的代码改进。因此,在应用复杂的模式之前,我们首先应该看看是否可以简化代码的可读性。

We’ll also see how to use functional programming. In Java, this applies from version 8 with the lambda expression syntax.

我们还将了解如何使用函数式编程。在 Java 中,从第 8 版开始使用 lambda 表达式语法。

3. Tests Legend

3. 测试 图例

Following the e-commerce discount example, we’ll create tests and check values in the discount months. For instance, from October to December. We’ll assert false otherwise. We’ll set random months that are either in or out of the ones allowed:

按照电子商务折扣示例,我们将创建测试并检查折扣月份的值。例如,从十月到十二月。否则我们将断言为假。我们将设置随机月份,这些月份要么在允许的月份之内,要么在允许的月份之外:

Month monthIn() {
    return Month.of(rand.ints(10, 13)
      .findFirst()
      .orElse(10));
}

Month monthNotIn() {
    return Month.of(rand.ints(1, 10)
      .findFirst()
      .orElse(1));
}

There could be multiple if conditions, although, for simplicity, we’ll assume just one if / else statement.

可以有多个 if 条件,但为了简单起见,我们假设只有一个 if / else 语句。

4. Use Switch

4.使用开关

An alternative to using an if logic is the switch command. Let’s see how we can use it in our example:

使用 if 逻辑的另一个替代方法是 switch 命令。让我们看看如何在示例中使用它:

boolean switchMonth(Month month) {
    switch (month) {
        case OCTOBER:
        case NOVEMBER:
        case DECEMBER:
            return true;
        default:
            return false;
    }
}

Notice it will be moving down and checking all valid months if required. Furthermore, we can improve this with the new switch syntax from Java 12:

请注意,如果需要,它将向下移动并检查所有有效月份。此外,我们还可以使用 Java 12 中的新 switch 语法来改进这一功能:

return switch (month) {
    case OCTOBER, NOVEMBER, DECEMBER -> true;
    default -> false;
};

Finally, we can do some testing to validate values in or not in the range:

最后,我们可以进行一些测试,以验证值是否在范围内:

assertTrue(switchMonth(monthIn()));
assertFalse(switchMonth(monthNotIn()));

5. Use Collections

5.使用收藏

We can use a collection to group what satisfies the if condition and check if a value belongs to it:

我们可以使用集合对满足 if 条件的内容进行分组,并检查某个值是否属于该集合

Set<Month> months = Set.of(OCTOBER, NOVEMBER, DECEMBER);

Let’s add some logic to see if the set contains a specific value:

让我们添加一些逻辑来查看集合是否包含特定值:

boolean contains(Month month) {
    if (months.contains(month)) {
        return true;
    }
    return false;
}

Likewise, we can add some unit tests:

同样,我们也可以添加一些单元测试:

assertTrue(contains(monthIn()));
assertFalse(contains(monthNotIn()));

6. Use Functional Programming

6.使用功能编程

We can use functional programming to convert the if / else logic to a function. Following this approach, we will have a predictable usage of our method syntax.

我们可以使用函数式编程if / else 逻辑转换为函数。采用这种方法后,我们的方法语法将具有可预测的用法。

6.1. Simple Predicate

6.1.简单谓词

Let’s still use the contains() method. However, we make it a lambda expression using a Predicate this time:

让我们继续使用 contains() 方法。不过,这次我们使用 Predicate 使其成为一个 lambda 表达式:

Predicate<Month> collectionPredicate = this::contains;

We are now sure that the Predicate is immutable with no intermediate variables. Its outcome is predictable and reusable in other contexts if we need to.

现在我们可以确定,谓词 是不可变的,没有中间变量。它的结果是可预测的,如果我们需要,还可以在其他上下文中重复使用。

Let’s check it out using the test() method:

让我们使用 test() 方法来检查一下:

assertTrue(collectionPredicate.test(monthIn()));
assertFalse(collectionPredicate.test(monthNotIn()));

6.2. Predicate Chain

6.2.谓词链

We can chain multiple Predicate adding our logic in an or condition:

我们可以将多个 Predicate 串联起来,在 or 条件中添加我们的逻辑:

Predicate<Month> orPredicate() {
    Predicate<Month> predicate = x -> x == OCTOBER;
    Predicate<Month> predicate1 = x -> x == NOVEMBER;
    Predicate<Month> predicate2 = x -> x == DECEMBER;

    return predicate.or(predicate1).or(predicate2);
}

We can then plug it in the if:

然后,我们就可以将其插入 if 中:

boolean predicateWithIf(Month month) {
    if (orPredicate().test(month)) {
        return true;
    }
    return false;
}

Let’s check this is working with a test:

让我们通过测试来检验一下它是否有效:

assertTrue(predicateWithIf(monthIn()));
assertFalse(predicateWithIf(monthNotIn()));

6.3. Predicate in Streams

6.3.流中的谓词

Similarly, we can use a Predicate in a Stream filter. Likewise, a lambda expression in a filter will replace and enhance the if logic. The if will eventually disappear. This is an advantage of functional programming while still keeping good performance and readability.

同样,我们可以在 Stream 过滤器中使用 Predicate 。同样,过滤器中的 lambda 表达式将取代并增强 if 逻辑。if 最终会消失。这是函数式编程的优势,同时还能保持良好的性能和可读性。

Let’s test this while parsing an input list of months:

让我们在解析输入的月份列表时测试一下:

List<Month> monthList = List.of(monthIn(), monthIn(), monthNotIn());

monthList.stream()
  .filter(this::contains)
  .forEach(m -> assertThat(m, is(in(months))));

We could also use the predicateWithIf() instead of the contains(). A lambda has no restrictions if it supports the method signature. For instance, it could be a static method.

我们还可以使用 predicateWithIf() 代替 contains().例如,它可以是一个 static 方法。

7. Conclusion

7.结论

In this tutorial, we learned how to improve the readability of multiple conditions in an if statement. We saw how to use a switch instead. Furthermore, we’ve also seen how to use a collection to check whether it contains a value. Finally, we saw how to adopt a functional approach using lambda expression. Predicate and Stream are less error-prone and will enhance code readability and maintenance.

在本教程中,我们学习了如何提高 if 语句中多个条件的可读性。我们看到了如何使用 switch 代替。此外,我们还了解了如何使用集合来检查它是否包含一个值。最后,我们还了解了如何使用 lambda 表达式来采用函数式方法。PredicateStream 不易出错,并将提高代码的可读性和维护性。

As always, the code presented in this article is available over on GitHub.

与往常一样,本文中介绍的代码可在 GitHub 上获取