Java中使用冒号的七种方式

在 Java 中,冒号字符(:)用于不同的上下文,并根据上下文的不同而具有不同的含义。

以下是 Java 中冒号的一些常用用法:

1、三元运算符
冒号在三元运算符 (? :) 中用作条件、条件为真时要执行的表达式和条件为假时要执行的表达式之间的分隔符。

int result = (condition) ? valueIfTrue : valueIfFalse;

Java 三元运算符是简单if/else语句的简写。假设我们有以下代码:

int x;
if (checkSomeCondition()) {
    x = 1;
}
else {
    x = 2;
}

使用三元运算符,我们可以缩短相同的代码:
x = checkSomeCondition() ? 1 : 2;

此外,三元运算符可以与其他语句配合使用,使我们的代码更具可读性:

boolean remoteCallResult = callRemoteApi();
LOG.info(String.format(
  "远程 API 调用 %s 成功的结果",
  remoteCallResult ?
"was" : "was not"
));

2、增强型 For 循环:
冒号用于增强 for 循环,以遍历数组、集合或其他可遍历对象中的元素。

for (Type variable : iterable) {
    // Loop body
}

3、Switch 语句中的 Case 语句
在 switch 语句中,冒号用于分隔 case 值和匹配该 case 时要执行的代码块。

switch (variable) {
    case value1:
        // Code block for value1
        break;
    case value2:
       
// Code block for value2
        break;
   
// ...
    default:
       
// Code block for default case
}


4、标签声明:
在 Java 中,冒号用于标记语句。标签语句通常与 break 或 continue 语句一起使用。

没有使用标签:

for (int i = 0; i < 10; i++) {
    for (int j = 0; j < 10; j++) {
        if (checkSomeCondition()) {
            break;
        }
    }
}

在这种情况下,break 关键字会使内循环停止执行,并将控制权返回给外循环。这是因为,在默认情况下,break 语句会将控制返回到最近的控制块的末尾。在本例中,就是指带有 j 变量的循环。让我们看看如何使用标签来改变这种行为。

首先,我们需要重写带有标签的循环:

outerLoop: for (int i = 0; i < 10; i++) {
    innerLoop: for (int j = 0; j < 10; j++) {
        if (checkSomeCondition()) {
            break outerLoop;
        }
    }
}

我们有同样的两个循环,但现在每个循环都有一个标签:。一个名为 outerLoop,另一个名为 innerLoop。我们可以注意到,break 语句后面跟了一个标签名称。这指示 JVM 将控制权转移到该标签语句的末尾,而不是默认行为。结果是,break 语句带着 i 变量退出了循环,有效地结束了两个循环。

5、在增强的 for 循环中分离组件(Java 10 及更高版本):
在 Java 10 及更高版本中,冒号在增强 for 循环中用于将元素重组为变量。这在处理记录集合时特别有用。

List<Point> points = List.of(new Point(1, 2), new Point(3, 4));
for (var (x, y) : points) {
    // Use x and y
}

6、 方法参考
作为 lambda 项目的一部分在 Java 8 中引入,方法引用也使用冒号字符。方法引用出现在整个 Java 的多个地方,最引人注目的是。让我们看几个例子。
假设我们有一个名称列表,并且想要将每个名称大写。在 lambda 和方法引用之前,我们可能会使用传统的for循环:

List<String> names = Arrays.asList("ross", "joey", "chandler");
List<String> upperCaseNames = new ArrayList<>();
for (String name : names) {
  upperCaseNames.add(name.toUpperCase());
}

我们可以通过流和方法引用来简化它:
List<String> names = Arrays.asList("ross", "joey", "chandler");
List<String> upperCaseNames = names
  .stream()
  .map(String::toUpperCase)
  .collect(Collectors.toList());

在本例中,我们使用对String类中的toUpperCase()实例方法的引用作为map()操作的一部分。
方法引用对于filter()操作也很有用,其中方法采用单个参数并返回boolean:

List<Animal> pets = Arrays.asList(new Cat(), new Dog(), new Parrot());
List<Animal> onlyDogs = pets
  .stream()
  .filter(Dog.class::isInstance)
  .collect(Collectors.toList());

方法引用中,方法签名参数必须等同于当前上下文的参数,例如上面map(String:toUpperCase)
String中必须有一个输入参数类型是String

public String toUpperCase(String myName){
   ....
}

如果参数有一个以外都不行,参数类型是String以外不行。这些都是上下文对对其限制导致。

最后,我们还可以使用带有方法引用的构造函数。我们通过将new运算符与类名和方法引用相结合来做到这一点:

List<Animal> pets = Arrays.asList(new Cat(), new Dog(), new Parrot());
Set<Animal> onlyDogs = pets
  .stream()
  .filter(Dog.class::isInstance)
  .collect(Collectors.toCollection(TreeSet::new));

在本例中,我们将过滤后的动物收集到新的TreeSet而不是List中。

7、断言
Java 语言的另一个经常被忽视的特性是断言。在 Java 1.4 中引入,assert关键字用于测试条件。如果该条件为false,则会引发错误。

让我们看一个例子:

void verifyConditions() {
    assert getConnection() != null : "Connection is null";
}

在此示例中,如果方法getConnection()的返回值为 null,则 JVM 会抛出AssertionError。冒号后面的字符串是可选的。它允许我们提供一条消息作为条件为false时抛出的错误的一部分。

我们应该记住默认情况下断言是禁用的。要使用它们,我们必须使用-ea命令行参数启用它们。

总之:这些是 Java 中冒号字符的一些常见用法。每种用法都有特定的含义,并在语言的语法和功能中发挥着不同的作用。