面试题答案
一键面试Java Lambda 表达式与函数式接口的内在联系
- 函数式接口定义:函数式接口是只包含一个抽象方法的接口。Java 8 为函数式接口提供了
@FunctionalInterface
注解(非必需,但建议使用),用于明确标识该接口是函数式接口,若接口中包含超过一个抽象方法,编译器会报错。例如:
@FunctionalInterface
interface MyFunction {
int apply(int num);
}
- Lambda 表达式适配函数式接口:Lambda 表达式是一种匿名函数,它可以作为函数式接口的实例。其语法形式为
(parameters) -> expression
或(parameters) -> { statements; }
。例如,对于上述MyFunction
接口,可以这样使用 Lambda 表达式:
MyFunction func = (num) -> num * 2;
int result = func.apply(5);
Lambda 表达式的参数列表、返回值类型必须与函数式接口中抽象方法的参数列表、返回值类型相匹配。
高并发场景下优化 Lambda 表达式和函数式接口操作大集合的方法及原理
- 原理:在高并发场景下,大集合的复杂操作(多条件过滤、多字段排序等)使用顺序流的 Lambda 表达式可能会性能不佳,因为所有操作在单线程中执行。而并行流利用多核 CPU 的优势,将集合分割成多个部分,并行处理这些部分,最后合并结果,从而提高性能。
- 优化方法:
- 使用并行流:将顺序流转换为并行流。在集合上调用
parallelStream()
方法即可。例如,假设有一个List<Person>
集合,Person
类有age
和name
字段,要对其进行多条件过滤和排序:
- 使用并行流:将顺序流转换为并行流。在集合上调用
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
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;
}
}
public class Main {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
// 初始化集合数据
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 30));
people.add(new Person("Charlie", 22));
List<Person> result = people.parallelStream()
.filter(person -> person.getAge() > 23)
.sorted(Comparator.comparingInt(Person::getAge).thenComparing(Person::getName))
.collect(Collectors.toList());
result.forEach(person -> System.out.println(person.getName() + " : " + person.getAge()));
}
}
在上述代码中,parallelStream()
将顺序流转换为并行流,filter
方法进行多条件过滤,sorted
方法进行多字段排序。并行流会利用多核 CPU 并行处理过滤和排序操作,提高性能。
- 减少中间操作:每一个中间操作(如 filter
、map
等)都会产生一个新的流,过多的中间操作会增加性能开销。尽量合并条件或减少不必要的转换,例如将多个 filter
合并为一个 filter
。
- 使用更高效的函数式接口实现:对于自定义的函数式接口,可以优化其实现逻辑,避免复杂的计算在每次调用时重复执行。如果可能,缓存一些计算结果。例如,在函数式接口的实现中使用 Supplier
来延迟计算,只有在真正需要时才执行计算。
通过以上方法,从 Lambda 表达式和函数式接口的角度,在高并发场景下对大集合的复杂操作进行优化,提升性能。