简介
双冒号运算操作符是类方法的句柄,lambda 表达式的一种简写,这种简写的学名叫 eta-conversion 或者叫 η-conversion。
通常的情况下:
把 x -> System.out.println(x) 简化为 System.out::println 的过程称之为 eta-conversion
把 System.out::println 简化为 x -> System.out.println(x) 的过程称之为 eta-expansion
双冒号运算就是 java 中的[方法引用]
。 [方法引用]
格式为:类名::方法名
。
注意是方法名哦,后面没有括号“()”的。为啥不要括号,因为这样的是式子并不代表一定会调用这个方法。这种式子一般是用作Lambda表达式,Lambda有所谓懒加载嘛,不要括号就是说,看情况调用方法。
示例说明
例如:
表达式:
person -> person.getAge();
可以替换成
Person::getAge
表达式
() -> new HashMap<>();
可以替换成
HashMap::new
这种 [方法引用] 或者说 [双冒号运算] 对应的参数类型是 Function<T, R> T 表示传入类型,R 表示返回类型。比如表达式 person -> person.getAge(); 传入参数是 person,返回值是 person.getAge() ,那么方法引用Person::getAge 就对应着 Function<Person,Integer> 类型。
具体例子
下面这段代码,进行的操作是,把List里面的String全部大写并返还新的ArrayList,在前面的例子中我们是这么写的:
@Test
public void convertTest() {
List<String> collected = new ArrayList<>();
collected.add("alpha");
collected.add("beta");
collected = collected.stream().map(string -> string.toUpperCase()).collect(Collectors.toList());
System.out.println(collected);
}
现在也可以被替换成下面的写法:
@Test
public void convertTest() {
List<String> collected = new ArrayList<>();
collected.add("alpha");
collected.add("beta");
collected = collected.stream().map(String::toUpperCase).collect(Collectors.toCollection(ArrayList::new));//注意发生的变化
System.out.println(collected);
}
常见的几种用法
在Java 8中,方法引用是Lambda表达式的一个非常有用的简化形式,它允许你直接引用现有方法而不必显式地创建Lambda表达式。方法引用使用双冒号(::
)操作符。
双冒号操作符(::
)在方法引用中有以下几种主要用法:
-
静态方法引用:
当你需要引用一个静态方法时,你可以使用类名加上双冒号和静态方法名。List<String> list = Arrays.asList("a1", "a2", "a3"); list.forEach(System.out::println);
在上面的例子中,
System.out::println
是对System.out
类中的println
静态方法的引用。 -
特定对象的实例方法引用:
如果你有一个特定的对象,并且你想引用该对象的一个实例方法,你可以使用对象名加上双冒号和实例方法名。String str = "Hello"; BiFunction<String, String, String> append = str::concat; String result = append.apply(" World", "!"); // 结果是 "Hello World!",但这不是真正的用法,因为concat只需要一个参数
注意:上面的例子并不是真正的
BiFunction
用法,因为String::concat
实际上只接受一个参数。但为了演示方法引用的语法,我仍然使用了它。 -
特定类型的任意对象的实例方法引用:
如果你想要引用某个类型对象的实例方法,而不指定具体的对象,你可以使用类名加上双冒号和实例方法名。这通常与函数式接口的方法参数类型相匹配。List<String> list = Arrays.asList("a1", "a2", "a3"); list.sort(String::compareToIgnoreCase);
在上面的例子中,
String::compareToIgnoreCase
是对String
类中的compareToIgnoreCase
实例方法的引用,它用于比较两个字符串(忽略大小写)。 -
构造器引用:
你也可以使用双冒号来引用构造器。这在你需要创建对象实例时特别有用。Supplier<String> stringSupplier = String::new; String newString = stringSupplier.get(); // 创建一个新的空字符串 Function<Integer, String> stringFromInt = Integer::toString; String stringFromIntResult = stringFromInt.apply(123); // 结果是 "123"
在上面的例子中,
String::new
是对String
类的默认构造器的引用,而Integer::toString
是对Integer
类的toString
方法的引用,该方法接受一个int
参数并返回一个String
。