Java 8 中的 :: 运算符(双冒号):完整指南及示例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Java 8 中的 :: 运算符(Double Colon):从新手到专家

\n\n

你是否曾经在编写 Java 8 代码时,看到过像 System.out::println 或 String::length 这样奇怪的构造?看起来像魔法,不是吗?实际上,这不是魔法,而是现代 Java 中最优雅的工具之一——双冒号运算符(也称为 double colon operator 或 方法引用)。

\n\n

在本文中,我们将从最基础的知识到高级技巧,全面解析 :: 运算符。你将学会编写更简洁、更优雅、更易读的代码。让我们开始吧!

\n\n

什么是 :: 运算符,为什么需要它?

\n\n

:: 运算符(double colon)是在 Java 8 中引入的,作为 lambda 表达式的语法糖。如果 lambda 表达式只是简单地调用一个现有方法,你可以用方法引用来替换它。这使代码更短、更具表现力。

\n\n

请自行比较:

\n\n
// Lambda 表达式\nlist.forEach(s -> System.out.println(s));\n\n// 方法引用(:: 运算符)\nlist.forEach(System.out::println);
\n\n

第二种写法不仅更短,而且直接表明:“对每个元素,调用 System.out 的 println 方法”。多么优雅!

\n\n

四种方法引用类型

\n\n

在 Java 8 中,有四种主要的 method reference 类型。让我们逐一通过示例来讲解。

\n\n

1. 引用静态方法

\n\n

语法:ClassName::staticMethodName

\n\n

示例:计算列表中偶数的数量。

\n\n
import java.util.Arrays;\nimport java.util.List;\n\npublic class StaticMethodReference {\n    public static boolean isEven(Integer number) {\n        return number % 2 == 0;\n    }\n\n    public static void main(String[] args) {\n        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);\n        \n        // Lambda\n        long countLambda = numbers.stream()\n                .filter(n -> StaticMethodReference.isEven(n))\n                .count();\n        \n        // 引用静态方法\n        long countRef = numbers.stream()\n                .filter(StaticMethodReference::isEven)\n                .count();\n        \n        System.out.println("偶数数量: " + countRef); // 3\n    }\n}
\n\n

请注意:我们并没有调用 isEven 方法——我们只是传递了对它的引用。Java 会自动将列表中的每个元素作为参数传入。

\n\n

2. 引用特定对象的实例方法

\n\n

语法:objectReference::instanceMethodName

\n\n

这种类型用于当你已经有一个特定对象,并且想要调用它的方法时。

\n\n
import java.util.Arrays;\nimport java.util.List;\n\npublic class InstanceMethodReference {\n    public static void main(String[] args) {\n        List<String> names = Arrays.asList("安娜", "鲍里斯", "维克多");\n        \n        // 创建一个 StringBuilder 对象\n        StringBuilder sb = new StringBuilder("名字: ");\n        \n        // Lambda\n        names.forEach(name -> sb.append(name).append(" "));\n        \n        // 引用实例方法\n        // (但 append 返回 StringBuilder,所以我们使用 lambda)\n        // 而对于 System.out.println - 则非常完美:\n        names.forEach(System.out::println);\n        \n        System.out.println(sb.toString()); // 名字: 安娜 鲍里斯 维克多\n    }\n}
\n\n

经典示例是 System.out::println。System.out 是一个具体的 PrintStream 对象,而 println 是它的方法。

\n\n

3. 引用特定类型任意对象的实例方法

\n\n

语法:ClassName::instanceMethodName

\n\n

这种类型经常与前一种混淆。这里我们不指定具体对象——而是说:“取这个类的任意对象,并调用它的方法”。

\n\n


                
                

博客

书籍推荐