赞
踩
方法引用是Java 8中一种简化Lambda表达式的方式,通过直接引用现有方法来代替Lambda表达式。
方法引用使得代码更加简洁和易读,特别是在处理函数式接口时,可以替代相对冗长的Lambda表达式,提高了代码的可维护性和可读性。
方法引用通常可以分为以下几种类型:
ClassName::staticMethodName
。objectInstance::instanceMethodName
。ClassName::new
。定义一个函数式接口,定义一个抽象方法 convert
,接收一个类型为 F
的参数,并返回一个类型为 T
的结果。
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
有一个静态方法 StringHelper
中的静态方法 toUpperCase
。
class StringHelper {
public static String toUpperCase(String str) {
return str.toUpperCase();
}
}
使用静态方法引用来创建一个 Converter
实例。
/**
* StringHelper::toUpperCase 就是静态方法引用,它引用了 StringHelper 类的 toUpperCase 方法,该方法的签名与 Converter 接口中的 convert 方法兼容
*/
Converter<String, String> converter = StringHelper::toUpperCase;
String convertedStr = converter.convert("hello");
System.out.println(convertedStr);
// 输出:
HELLO
定义一个类 StringUtils
,有一个实例方法 startsWithIgnoreCase
。
class StringUtils {
public boolean startsWithIgnoreCase(String str, String prefix) {
// 检查一个字符串是否以另一个字符串开头(忽略大小写)
return str.toLowerCase().startsWith(prefix.toLowerCase());
}
}
使用实例方法引用来创建一个 BiPredicate
实例:
/**
* 方法引用允许我们在 BiPredicate 接口的上下文中使用 startsWithIgnoreCase 方法作为一个函数,第一个参数作为方法的调用者(即 stringUtils 对象),第二个参数作为方法的参数传递
*/
StringUtils stringUtils = new StringUtils();
// 使用实例方法引用创建 BiPredicate 实例
BiPredicate<String, String> startsWithIgnoreCase = stringUtils::startsWithIgnoreCase;
// 测试 startsWithIgnoreCase 方法引用的效果,调用 test 方法来检查字符串 "Java" 是否以 "ja" 开头(忽略大小写)
boolean result = startsWithIgnoreCase.test("Java", "ja");
System.out.println(result);
// 输出:
true
定义一个类 Person
,它有一个构造方法 Person(String name, int age)
。
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
使用构造方法引用来创建一个 Supplier
实例。
// 使用构造方法引用创建 Supplier 实例
Supplier<Person> personSupplier = Person::new;
// 获取 Person 对象
Person person = personSupplier.get();
// 设置 Person 对象的属性
person = new Person("Alice", 30);
System.out.println(person.getName() + ", " + person.getAge());
// 输出:
Alice, 30
在这里,Person::new
是构造方法引用,它引用了 Person
类的构造方法,根据 Supplier
的函数签名,Java 编译器会自动推断使用哪个构造方法。
是不是感觉构造方法引用有点多余,这样有什么好处吗?为什么不直接new一个构造函数,这样不显得多此一举吗 ?
使用构造方法引用和 Supplier
接口结合起来的好处:
Supplier
实例时,实际的对象并没有立即被创建。Supplier
的 get()
方法时,才会真正创建对象。这种方式可以延迟对象的实例化,直到真正需要使用它时。Supplier
是一个函数式接口,它通常用于表示一个供给型的操作,它不接受任何参数,返回一个指定类型的结果。Java 8 引入了接口的默认方法,这是一种在接口中定义具有默认实现的方法的方式。默认方法允许接口在不破坏现有实现的情况下,向现有的接口添加新的方法。
特点和用途:
interface Vehicle {
// 抽象方法
void start();
// 默认方法
default void stop() {
System.out.println("Vehicle stopped");
}
}
class Car implements Vehicle {
@Override
public void start() {
System.out.println("Car started");
}
// 可选:覆盖默认方法
@Override
public void stop() {
System.out.println("Car stopped");
}
}
public class Main {
public static void main(String[] args) {
Vehicle car = new Car();
// 输出: Car started
car.start();
// 输出: Car stopped
car.stop();
}
}
一个类实现了多个接口,这些接口中有相同签名的默认方法(包括继承关系),那么编译器会要求显式地覆盖冲突的默认方法,以消除二义性。
冲突主要存在的情况:
interface InterfaceA {
default void greet() {
System.out.println("Hello from InterfaceA");
}
}
interface InterfaceB {
default void greet() {
System.out.println("Hello from InterfaceB");
}
}
// 实现类实现了多个接口,这些接口中有同名的默认方法 greet()
class MyClass implements InterfaceA, InterfaceB {
// 需要手动实现 greet() 方法,消除二义性
@Override
public void greet() {
// 可以选择调用 InterfaceA 的默认实现
InterfaceA.super.greet();
// 也可以自己实现
}
}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.greet();
}
}
// 输出:
Hello from InterfaceA
接口静态方法是Java 8引入的一个重要特性,它们扩展了接口的功能,使得接口可以包含静态的方法实现。这种方法通常用于定义一些通用的工具方法,或者提供与接口实例无关的共享代码。静态方法的引入使得Java接口在语法上更加灵活和功能强大。
特点和用途:
static
关键字声明,并且可以有方法体。interface UtilityInterface {
// 静态方法
static void printMessage(String message) {
System.out.println("Message from interface: " + message);
}
// 抽象方法
void processData(String data);
}
class MyClass implements UtilityInterface {
@Override
public void processData(String data) {
System.out.println("Processing data: " + data);
}
}
public class Main {
public static void main(String[] args) {
// 调用静态方法
UtilityInterface.printMessage("Hello, world!");
MyClass obj = new MyClass();
obj.processData("Sample Data");
}
}
集合类(如List、Set、Map等)引入了一个新的方法
forEach()
,用于简化集合的遍历操作。这个方法可以在集合类的实例上直接调用,接受一个函数式接口的实现作为参数,用来定义遍历集合时的操作。
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 使用 forEach() 遍历输出每个元素
names.forEach(name -> System.out.println(name));
// 也可以使用方法引用
names.forEach(System.out::println);
}
}
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Integer> numbers = new HashSet<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
// 使用 forEach() 遍历输出每个元素
numbers.forEach(number -> System.out.println(number));
}
}
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");
// 使用 forEach() 遍历输出每个键值对
map.forEach((key, value) -> System.out.println(key + " -> " + value));
}
}
注意事项:
forEach()
方法不能保证集合元素的顺序,具体取决于集合的实现类。ConcurrentModificationException
异常。好的木材并不在顺境中生长,风越强,树越壮
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。