Java 8 中的 :: 运算符(Double Colon):从新手到专家
\n\n你是否曾经在编写 Java 8 代码时,看到过像 System.out::println 或 String::length 这样奇怪的构造?看起来像魔法,不是吗?实际上,这不是魔法,而是现代 Java 中最优雅的工具之一——双冒号运算符(也称为 double colon operator 或 方法引用)。
在本文中,我们将从最基础的知识到高级技巧,全面解析 :: 运算符。你将学会编写更简洁、更优雅、更易读的代码。让我们开始吧!
什么是 :: 运算符,为什么需要它?
\n\n:: 运算符(double colon)是在 Java 8 中引入的,作为 lambda 表达式的语法糖。如果 lambda 表达式只是简单地调用一个现有方法,你可以用方法引用来替换它。这使代码更短、更具表现力。
请自行比较:
\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\n1. 引用静态方法
\n\n语法:ClassName::staticMethodName
示例:计算列表中偶数的数量。
\n\nimport 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 会自动将列表中的每个元素作为参数传入。
2. 引用特定对象的实例方法
\n\n语法:objectReference::instanceMethodName
这种类型用于当你已经有一个特定对象,并且想要调用它的方法时。
\n\nimport 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 是它的方法。
3. 引用特定类型任意对象的实例方法
\n\n语法:ClassName::instanceMethodName
这种类型经常与前一种混淆。这里我们不指定具体对象——而是说:“取这个类的任意对象,并调用它的方法”。
\n\n博客
书籍推荐
推荐阅读