System.out::println 中的双冒号 :: 是 Java 8 引入的 方法引用(Method Reference) 运算符。
#方法引用是什么?
方法引用是一种简化 Lambda 表达式的语法糖,用于直接指向已经存在的方法。
等价关系:
java
// Lambda 表达式
x -> System.out.println(x)
// 方法引用(等价写法)
System.out::println
两者功能完全相同,但方法引用更加简洁。
#方法引用的四种类型
1. 静态方法引用 - Class::staticMethod
java
// Lambda 表达式
Function<String, Integer> parser1 = s -> Integer.parseInt(s);
// 方法引用
Function<String, Integer> parser2 = Integer::parseInt;
// 使用
System.out.println(parser2.apply("123")); // 输出: 123
2. 实例方法引用 - instance::instanceMethod
java
// Lambda 表达式
Consumer<String> printer1 = s -> System.out.println(s);
// 方法引用(System.out 是一个实例)
Consumer<String> printer2 = System.out::println;
// 使用
printer2.accept("Hello World"); // 输出: Hello World
3. 特定类型的任意对象的实例方法 - Class::instanceMethod
java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Lambda 表达式
names.sort((s1, s2) -> s1.compareTo(s2));
// 方法引用
names.sort(String::compareTo);
// 另一种常见用法
List<String> upperNames = names.stream()
.map(String::toUpperCase) // 等价于 s -> s.toUpperCase()
.collect(Collectors.toList());
4. 构造方法引用 - Class::new
java
// Lambda 表达式
Supplier<List<String>> supplier1 = () -> new ArrayList<>();
// 方法引用
Supplier<List<String>> supplier2 = ArrayList::new;
// 使用
List<String> list = supplier2.get();
#深入理解 System.out::println
语法解析:
System.out:PrintStream 类的实例
println:PrintStream 类的实例方法
System.out::println:引用 System.out 对象的 println 方法
实际应用场景:
java
List<String> fruits = Arrays.asList("Apple", "Banana", "Orange");
// 传统 for 循环
for (String fruit : fruits) {
System.out.println(fruit);
}
// 使用 Stream + 方法引用(推荐)
fruits.stream()
.forEach(System.out::println);
// 等价于:
fruits.stream()
.forEach(fruit -> System.out.println(fruit));
#方法引用 vs Lambda 表达式
何时使用方法引用:
java
// ? 推荐使用方法引用(更简洁)
list.forEach(System.out::println);
list.stream().map(String::toUpperCase);
// ? 不必要的 Lambda(冗长)
list.forEach(x -> System.out.println(x));
list.stream().map(s -> s.toUpperCase());
何时使用 Lambda 表达式:
java
// ? 需要复杂逻辑时使用 Lambda
list.stream()
.filter(s -> s != null && !s.isEmpty()) // 方法引用无法表达复杂条件
.map(s -> "Item: " + s.toUpperCase()) // 需要字符串拼接
.forEach(System.out::println);
#更多实用示例
在 Stream API 中的应用:
java
List<String> names = Arrays.asList("john", "jane", "bob", null, "");
// 链式方法引用
List<String> result = names.stream()
.filter(Objects::nonNull) // 静态方法引用
.filter(String::isEmpty).negate() // 实例方法引用
.map(String::toUpperCase) // 实例方法引用
.sorted(String::compareToIgnoreCase)// 实例方法引用
.collect(Collectors.toList());
result.forEach(System.out::println);
#自定义方法引用:
java
class StringUtils {
// 自定义静态方法
public static boolean isPalindrome(String s) {
if (s == null) return false;
return new StringBuilder(s).reverse().toString().equals(s);
}
}
// 使用方法引用
List<String> words = Arrays.asList("radar", "hello", "level", "world");
List<String> palindromes = words.stream()
.filter(StringUtils::isPalindrome) // 自定义静态方法引用
.collect(Collectors.toList());
palindromes.forEach(System.out::println); // 输出: radar, level
#性能考虑
方法引用和 Lambda 表达式在性能上没有显著差异,因为:
两者都会在运行时生成类似的字节码
JVM 会对热点代码进行即时编译优化
选择依据应该是代码的可读性而非性能
可读性对比:
java
// ? 更易读
users.stream()
.map(User::getName)
.filter(name -> name != null && name.length() > 0)
.forEach(System.out::println);
// ? 较难理解
users.stream()
.map(user -> user.getName())
.filter(name -> name != null && name.length() > 0)
.forEach(name -> System.out.println(name));
#总结
语法 |类型 |等价 Lambda
System.out::println 实例方法引用 |x -> System.out.println(x)
String::toUpperCase 特定类型方法引用|s -> s.toUpperCase()
Integer::parseInt 静态方法引用 |s -> Integer.parseInt(s)
ArrayList::new 构造方法引用 |() -> new ArrayList<>()
核心要点:
:: 是方法引用运算符
System.out::println 是对 println 方法的引用
方法引用让代码更简洁、更易读
在简单场景下替代 Lambda 表达式
广泛用于 Stream API 和函数式编程
方法引用是现代 Java 编程中的重要特性,熟练掌握能让你的代码更加优雅和函数式!