概念
特点:
Lambda是一个匿名函数,是对匿名函数的简写形式,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递),其最主要的作用就是简化代码,提高开发效率。它写起来就一个特点——紧凑!
与匿名内部类的区别:
1、类型限定不同,匿名内部类可以是接口、抽象类、实体类,而Lambda表达式只能是接口。
2、实现方式不同,Lambda表达式的字节码文件会自动生成,而匿名内部类会生成一个.class文件,名字通常是“外部类类名$序号.class”的格式。
3、功能范围不同,匿名内部类可以定义多个方法,包括构造函数、实例方法和静态方法。它们还可以包含初始化块和变量。而Lambda表达式只能实现一个方法,这个方法必须是一个函数式接口的方法。函数式接口是一个只包含一个抽象(java9以前)方法的接口。
语法
他的写法是使用一个->符号,箭头将Lambda表达式分为左右两部分
左边写的是实现的这个接口中的抽象方法中的形参列表,右边就是对抽象方法的处理
基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }
例如:
List<String> list = Arrays.asList("apple","orange","banana");
//写法一
list.forEach(s -> {
System.out.print(s);
});
//写法二
list.forEach(s -> System.out.print(s));
//写法三
list.forEach(System.out::print);
上述代码三种写法都是遍历list并将各个元素打印,能达到同样的效果。
其中第三个写法是用了Java 8引入的Lambda表达式和方法引用功能
System.out::print: 这是一个方法引用,它引用了System.out
类的print
方法。print
方法接受一个String
参数并打印,但它不返回任何值(即返回void
)。由于print
方法满足Consumer
接口(接受一个参数并且没有返回值),因此我们可以将其用作forEach
方法的参数。
可以看到该方法确实是实现了Consumer接口,另外可以注意到该接口上面有一个@FunctionalInterface注解,表示该接口为函数式接口
Consumer接口源码如下:
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
确实是仅有一个方法,但是为什么该方法可以是default的?
原因:从Java 9开始,也可以包含默认方法、静态方法和java.lang.Object
的方法
Lambda基本用法
简化自定义接口中方法的使用
示例:
public static void main(String[] args) {
//Lambda写法
abc ac = ()->{
System.out.println("a");
};
ac.a();
//常规调用
abc aa = new abc() {
@Override
public void a() {
System.out.println("b");
}
};
ac.a();
}
}
interface abc{
void a();
}
在集合中的使用
遍历forEach、过滤filter、映射map、排序sorted、查找match、聚合reduce
示例:用map将集合中的元素映射为其长度
public static void map(List<String> list){
List<Integer> list1 = new ArrayList<>();
for (String s:
list) {
list1.add(s.length());
}
list1.forEach(System.out::print);
System.out.println();
//Lambda写法
List<Integer> list2 = list.stream().map(s -> s.length()).collect(Collectors.toList());
list2.forEach(s -> System.out.print(s));
}
示例:用forEach遍历集合元素
public static void each(List<String> list){
for (String s:
list) {
System.out.print(s);
}
list.forEach(System.out::println);
}
示例:用filter筛选集合中以“a“开头的元素
public static void filter(List<String> list){
List<String> list1 = new ArrayList<>();
for (String s:
list) {
if(s.startsWith("a")){
list1.add(s);
}
}
list1.forEach(System.out::print);
System.out.println();
//Lambda写法
List<String> list2 = list.stream().filter(s->s.startsWith("a")).collect(Collectors.toList());
list2.forEach(s -> System.out.print(s));
}
示例:聚合reduce,求集合中所有元素之和
public static void theSum(List<Integer> list){
int sum = 0;
for (int a:
list) {
sum+=a;
}
System.out.println(sum);
//使用lambda表达式
//reduce(初始值,(参数)-> 函数);
int sum1 = list.stream().reduce(0,(a,b) -> a + b);
System.out.println(sum1);
}
示例:使用anyMatch,验证集合中是否存在符合条件的元素
//查找集合中是否存在符合条件的元素
public static void find(List<String> list){
Boolean k = false;
for (String a:
list ) {
if (a.length()==5){
k = true;
break;
}
}
System.out.println(k);
//lambda表达式写法
Boolean i = list.stream().anyMatch(s->s.length()==5);
System.out.println(i);
}
综合示例:
public static void UpSort(List<String> list){
List<String> list1 = new ArrayList<>();
for (String s:
list) {
if (s.startsWith("a")){
list1.add(s.toUpperCase());
}
}
Collections.sort(list1);
list1.forEach(System.out::print);
System.out.println();
List<String> list2 = list.stream().filter(s -> s.startsWith("a")).map(s->s.toUpperCase()).sorted().collect(Collectors.toList());
list2.forEach(System.out::print);
System.out.println();
}
Lambda表达式的使用
1、实现java的函数式接口。
2、lambda表达式作为参数。
// 定义一个方法,接受一个函数式接口作为参数
public static void processStrings(List<String> strings, Consumer<String> processor) {
strings.forEach(processor);
}
// 调用该方法,并传递一个Lambda表达式作为参数
processStrings(Arrays.asList("a", "b", "c"), s -> System.out.println(s.toUpperCase()));
3、类型推断
在Lambda表达式中,编译器可以通过上下文推断出参数的类型,从而简化Lambda表达式的写法。