Java8中方法引用的用法
Stream流和Lambda表达式不懂的可以看我之前的文章:
觉得方法引用有点难记,所以又重新专门梳理一遍它的用法。
1、静态方法的引用
静态方法引用用于直接调用类的静态方法。语法是 ClassName::staticMethod。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StringToIntExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("1", "2", "3");
// 使用 Integer::parseInt 将字符串转换为整型
List<Integer> integers = names.stream()
.map(Integer::parseInt)
.collect(Collectors.toList());
System.out.println(integers); // 输出: [1, 2, 3]
}
}
这里解释一下,如果不用方法引用如果用lambda表达式应该怎么写
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class LambdaExpressionExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("1", "2", "3");
// 使用 lambda 表达式创建新的 ArrayList
List<Integer> integers = names.stream()
.map(s -> Integer.parseInt(s))
.collect(Collectors.toList());
System.out.println(upperCaseNames); // 输出: [1, 2, 3]
}
}
这里之所以可以这么写是因为lambda表达式可以用于简写函数式接口,而这里的s -> Integer.parseInt(s)
就是一个函数式接口的简写,如下,Function接口的apply方法就是接收一个泛型参数,返回一个泛型类型的值。
所以也可以用lambda表达式实现,之所以说可以换成Integer::parseInt
是因为刚好在Integer类里面有一个可以实现相同功能的静态方法,可以用来做替代。
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
甚至还可以换成最原始的匿名内部类的写法,因为lambda表达式是可以替代匿名内部类的。这样就可以完整的看出它的不同的简写的来由了。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.function.Function;
public class AnonymousInnerClassExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("1", "2", "3");
// 使用匿名内部类创建新的 ArrayList
List<Integer> integers = names.stream()
.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
})
.collect(Collectors.toList());
System.out.println(integers); // 输出: [1, 2, 3]
}
}
2、实例方法引用
实例方法引用用于调用对象的实例方法。语法是 object::instanceMethod。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class InstanceMethodReferenceExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
String prefix = "User: ";
// 使用实例方法引用添加前缀
List<String> prefixedNames = names.stream()
.map(prefix::concat)
.collect(Collectors.toList());
System.out.println(prefixedNames); // 输出: [User: Alice, User: Bob, User: Charlie]
}
}
比如在转化成lambda表达式的写法
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class LambdaExpressionExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
String prefix = "User: ";
// 使用 lambda 表达式添加前缀
List<String> prefixedNames = names.stream()
.map(s -> prefix.concat(s))
.collect(Collectors.toList());
System.out.println(prefixedNames); // 输出: [User: Alice, User: Bob, User: Charlie]
}
}
匿名内部类写法
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.function.Function;
public class AnonymousInnerClassExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
String prefix = "User: ";
// 使用匿名内部类添加前缀
List<String> prefixedNames = names.stream()
.map(new Function<String, String>() {
@Override
public String apply(String s) {
return prefix.concat(s);
}
})
.collect(Collectors.toList());
System.out.println(prefixedNames); // 输出: [User: Alice, User: Bob, User: Charlie]
}
}
相信你看了上面了几个例子之后一定也非常明了了。
3、类的实例方法引用
语法是 ClassName::instanceMethod
。用于调用类里的实例方法。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class SpecificInstanceMethodReferenceExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用特定对象的实例方法引用比较字符串长度
names.sort(String::compareToIgnoreCase);
System.out.println(names); // 输出: [Alice, Bob, Charlie]
}
}
String::compareToIgnoreCase:这是类的实例方法引用。compareToIgnoreCase 是 String 类的一个实例方法,用于忽略大小写比较两个字符串。
- 使用 Comparator 实现
import java.util.Arrays;
import java.util.List;
import java.util.Comparator;
public class SpecificInstanceMethodReferenceExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用特定对象的实例方法引用比较字符串长度
names.sort(new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareToIgnoreCase(s2);
}
});
System.out.println(names); // 输出: [Alice, Bob, Charlie]
}
}
哪些类可以使用类的实例方法引用?
类的实例方法引用可以用于任何具有实例方法的类。实例方法是指那些需要通过类的实例(对象)来调用的方法。以下是一些常见的类及其实例方法引用的例子:
-
String
类compareToIgnoreCase
:忽略大小写比较两个字符串。toLowerCase
:将字符串转换为小写。toUpperCase
:将字符串转换为大写。trim
:去除字符串两端的空白字符。
import java.util.Arrays; import java.util.List; public class StringMethodReferenceExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); // 使用类的实例方法引用比较字符串 names.sort(String::compareToIgnoreCase); System.out.println(names); // 输出: [Alice, Bob, Charlie] // 使用类的实例方法引用转换为大写 List<String> upperCaseNames = names.stream() .map(String::toUpperCase) .collect(Collectors.toList()); System.out.println(upperCaseNames); // 输出: [ALICE, BOB, CHARLIE] } }
-
Integer
类intValue
:将Integer
对象转换为int
值。toString
:将Integer
对象转换为字符串。
-
自定义类
- 您可以在自定义类中定义实例方法,并使用方法引用来引用这些方法。这个例子其实就很常见了,日常开发就会为了获取对象的一个属性(如果想获取多个属性的话可以考虑重写to)
import java.util.Arrays; import java.util.List; class Person { private String name; public Person(String name) { this.name = name; } public String getName() { return name; } } public class CustomClassMethodReferenceExample { public static void main(String[] args) { List<Person> people = Arrays.asList( new Person("Alice"), new Person("Bob"), new Person("Charlie") ); // 使用类的实例方法引用获取名字 List<String> names = people.stream() .map(Person::getName) .collect(Collectors.toList()); System.out.println(names); // 输出: [Alice, Bob, Charlie] } }
4、构造器引用
构造器引用用于直接调用类的构造方法。语法是 ClassName::new
。
让我们来看一个更实用的构造器引用的例子。假设我们有一个 Person
类,我们希望从一个包含名字的字符串列表中创建 Person
对象的列表。我们将使用构造器引用来实现这一点。
定义 Person
类
class Person {
private String name;
private int age;
public Person(String name) {
this.name = name;
this.age = 0; // 默认年龄为 0
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
使用构造器引用创建 Person
对象的列表
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ConstructorReferenceExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用构造器引用创建新的 Person 对象列表
List<Person> people = names.stream()
.map(Person::new)
.collect(Collectors.toList());
// 输出结果
for (Person person : people) {
System.out.println(person); // 输出: Person{name='Alice', age=0}, Person{name='Bob', age=0}, Person{name='Charlie', age=0}
}
}
}