Java - Lambda
一.Lambda简介
Lambda是Java 8的一个新特性,可以看做是一个匿名函数
使用Lambda表达式可以非常简洁的对一个接口进行实现
二.Lambda对接口的要求
要求接口中抽象方法只能有一个
可使用@FunctionnalInterface将一个接口修饰为函数式接口
此时这个接口内只能有一个抽象方法,声明多个抽象方法将会报错
接口中的default方法不算抽象方法
三.Lambda表达式基础语法
Lambda是一个匿名函数
参数列表 方法体
() : 描述参数列表
{} : 描述方法体
-> : Lambda运算符,读作goes to
四.Lambda表达式语法精简
//定义的接口
@FunctionalInterface
public interface NoneReturnMultiParameter { void test(int x, int y);}
@FunctionalInterface
public interface NoneReturnNoneParameter { void test();}
@FunctionalInterface
public interface NoneReturnOneParameter { void test(int x);}
@FunctionalInterface
public interface OneReturnNoneParameter { int test();}
@FunctionalInterface
public interface OneReturnOneParameter { int test(int x);}
@FunctionalInterface
public interface ReturnMultiParameter { int test(int x, int y);}
//实现
ReturnMultiParameter lambda1 = (int a, int b) -> {
System.out.println(a + b);
return a + b;
};
lambda1.test(10, 20);
// 精简1.lambda可以省略参数类型
// 但是有多个参数时,要省略参数类型必须都省略,不能一个省略,另外一个不省略
ReturnMultiParameter lambda2 = (a, b) -> {
System.out.println(a + b);
return a + b;
};
lambda1.test(10, 20);
//精简2.当参数体中只要一个参数时,可以省略(),参数为空或有多个参数时不可省略
NoneReturnOneParameter lambda3 = a -> {
System.out.println(a);
};
lambda3.test(10);
//精简3.当方法体中只有一条语句时,可以省略{}
NoneReturnMultiParameter lambda4 = (a, b) -> System.out.println(1);
//精简4.当方法体中只有一行返回语句时,可以省略{},但是也必须省略return语句
ReturnMultiParameter lambda5 = (a, b) -> a + b;
lambda5.test(10, 20);
OneReturnOneParameter lambda6 = a -> a;
lambda6.test(10);
五.Lambda表达式函数引用
class Sum {
public int cal(int a, int b) {return a + b;}
}
//1.引用函数的参数数量和参数类型以及返回值类型必须和实现接口严格一致,不支持多态
//2.若被引用函数为静态方法,则可通过类名::方法名引用,若不是静态方法,则需通过 实现::方法名 引用
Sum sum = new Sum();
ReturnMultiParameter lambda = sum::cal;
System.out.println(lambda.test(10, 20));
构造方法引用
//实体类
public class Person {
public Person() {System.out.println("无参构造执行");}
public Person(String name, Integer age) {System.out.println("有参构造执行");}
}
//接口
interface PersonCreate {Person getPerson();}
interface PersonCreate2 {Person getPerson(String name, Integer age);}
// 根据接口中的参数类型和数量选择对应的构造函数
PersonCreate lambda1 = Person::new;
Person person = lambda1.getPerson();//无参
PersonCreate2 lambda2 = Person::new;
Person person2 = lambda2.getPerson("liuyu", 18);//有参
不能访问接口中的Default函数
NoneReturnOneParameter lambda2 = a -> {
getDouble(a);
};
十.系统内置函数式接口
Predicate<T> 参数T 返回值boolean
IntPredicate int-->boolean
LongPredicate long-->boolean
DoublePredicate double-->boolean
Consumer<T> 参数T 返回值 void
IntConsumer int --> void
LongConsumer long --> void
DoubleConsumer double --> void
Function<T, R> 参数T 返回值R
IntFunction<R> int --> R
LongFunction<R> long --> R
DoubleFunction<R> double --> R
IntToLongFunction int --> long
IntToDoubleFunction int --> double
LongToIntFunction long --> int
LongToDoubleFunction long --> double
DoubleToIntFunction double --> int
DoubleToLongFunction double --> long
Supplier<T> :参数无 返回值T
UnaryOperator<T> :参数T 返回值T
BinaryOperator<T> :参数T,T 返回值T
BiFunction<T, U, R> :参数T,U 返回值R
BiPredicate<T, U> :参数T,U 返回值boolean
BiConsumer<T, U> :参数T,U 返回值void
十一.Streams
java.util.Stream 表示了某一种元素的序列,在这些元素上可以进行各种操作。Stream操作可以是中间操作,也可以是完结操作。
完结操作会返回具体的值,而中间操作会返回流对象本身
可以通过多次调用同一个流操作方法将操作结果串起来(就像StringBuffer的append方法一样)
Stream是在一个源的基础上创建出来的,例如java.util.Collection中的list或者set(map不能作为Stream的源)
Stream操作往往可以通过顺序或者并行两种方式来执行。
可以直接通过调用Collections.stream()或者Collection.parallelStream()方法来创建一个流对象
例如
List<String> stringCollection = new ArrayList<>();
stringCollection.stream()
Filter(中间操作)
Filter接受一个predicate接口类型的变量,并将所有流对象中的元素进行过滤
ForEach(完结操作)
ForEach接受一个function接口类型的变量,用来执行对每一个元素的操作
stringCollection
.stream()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
Sorted(中间操作)
返回一个排过序的流对象的视图。流对象中的元素会按照自然顺序进行排序,也可由你自己指定一个Comparator接口来改变排序规则
注:
sorted只是创建一个流对象排序的视图,而不会改变原来集合中元素的顺序。原来集合中的元素顺序是没有改变的
Map(中间操作)
通过给定的方法,能够把流对象中的每一个元素对应到另一个对象上。下面的例子就演示了如何把每个string都转换成大写的string.
不但如此,你还可以把每一种对象映射成为其他类型。对于带泛型结果的流对象,具体的类型还要由传递给map的泛型方法来决定。
stringCollection
.stream()
.map(String::toUpperCase)
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);
Match(终结操作)
匹配操作有多种不同的类型,都是判断某一种规则是否与流对象相吻合
所有的匹配操作都是终结操作,只返回一个boolean类型的结果
//List<String> stringCollection = new ArrayList<>();
boolean anyStartsWithA =
stringCollection
.stream()
.anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true
boolean allStartsWithA = stringCollection
.stream()
.allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA); // false
boolean noneStartsWithZ = stringCollection
.stream()
.noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // true
Count(完结操作)
返回一个数值,标识当前流对象中包含的元素数量
long startsWithB =
stringCollection
.stream()
.filter((s) -> s.startsWith("b"))
.count();
System.out.println(startsWithB); // 3
Reduce(完结操作)
通过某一个方法,对元素进行削减操作。操作的结果会放在一个Optional变量中返回
Optional<String> reduced =
stringCollection
.stream()
.sorted()
.reduce((s1, s2) -> s1 + "#" + s2);
Parallel Streams
流操作可以是顺序的,也可以是并行的。顺序操作通过单线程执行,而并行操作则通过多线程执行
//串行排序
long count = values.stream().sorted().count();
//并行排序
long count = values.parallelStream().sorted().count();
十一.闭包
int num = 10
Consumer<Integer> consumer = (a) -> {
System.out.println(num);
System.out.println(++num);//会报错
};
++num; //会报错
consumer.accept(20);
//当lambda引用局部变量时,此变量会自动被编译器加上final修饰,在任何地方都不能对变量进行修改