使用Lambda表达式开发

  • Post author:
  • Post category:其他


先了解下Lambda的基础语法:


左侧

:lambda表达式的参数列表


右侧

:lambda表达式中所需要执行的功能,即lambda函数体

lambda表达式语法格式:

1、无参数,无返回值的用法 :() -> System.out.println(“hello lambda”);

2、有一个参数,无返回值的用法: (x) -> System.out.println(x); 或者 x -> System.out.println(x); 一个参数,可以省略参数的小括号

3、有两个参数,有返回值的:(x, y) -> x + y

方法的引用的语法,主要有三类



1.指向静态方法的方法引用,例如Integer的parseInt方法 ,可以写成Integer::parseInt

类::静态方法名

2.指向任意类型实例方法的方法引用,例如String的length方法,写成String::length;

类::实例方法名(也就是非静态方法)

3.指向现有对象的实例方法的方法引用

对象::实例方法名

4、构造器的引用:对于一个现有构造函数,你可以利用它的名称和关键字new来创建它的一个引用

ClassName::new


举例子:

/*************** 方法的引用 ****************/
// 类::静态方法名(compare是静态方法)
Comparator<Integer> cam1 = (x, y) -> Integer.compare(x,y);
System.out.println(cam1.compare(3, 2));
Comparator<Integer> cam = Integer::compare;
System.out.println(cam.compare(3, 2));
// 类::实例方法名。(equals是非静态方法)
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
System.out.println(bp.test("a", "b"));
BiPredicate<String, String> bp1 = String::equals;
System.out.println(bp1.test("a", "b"));

// 对象::实例方法名
Consumer<String> con1 = x -> System.out.println(x);
con1.accept("abc");
Consumer<String> con = System.out::println;
con.accept("abc");

Emp emp = new Emp("上海", "xiaoMIng", 18);
Supplier<String> supper1 = () -> emp.getAddress();
System.out.println(supper1.get());
Supplier<String> supper = emp::getAddress;
System.out.println(supper.get());

/*************** 构造器的引用 ****************/
// 无参构造函数,创建实例
Supplier<Emp> supper2 = () -> new Emp();
Supplier<Emp> supper3 = Emp::new;
Emp emp1 = supper3.get();
emp1.setAddress("上海");
// 一个参数
Function<String, Emp> fun = address -> new Emp(address);
Function<String, Emp> fun1 = Emp::new;
System.out.println(fun1.apply("beijing"));
// 两个参数
BiFunction<String, Integer, Emp> bFun = (name, age) -> new Emp(name, age);
BiFunction<String, Integer, Emp> bFun1 = Emp::new;
System.out.println(bFun1.apply("xiaohong", 18));


至于是选择Consumer,Supplier,Function,BiFunction中的哪一个需要根据你的参数列表,是否有无返回值,返回值类型来决定。

在java8中,lambda表达式所用的接口,必须是函数式接口。

那么怎么定义一个函数式接口。函数式接口定义:接口中只有一个抽象方法的接口,称为函数式接口;

可以使用@FunctionalInterface注解修饰,对该接口做检查;如果接口里,有多个抽象方法,使用该注解,会有语法错误。

1、Consumer<T> 消费型接口:void accept(T t);

2、Supplier<T> 供给型接口。T get();

3.Function<T,R> 函数型接口,R apply(T t);

4.Predicate<T> 断言型接口,或者判断型的接口:boolean test(T t);

JDK 1.8之前已有的函数式接口:

java.lang.Runnable

java.util.concurrent.Callable

java.security.PrivilegedAction

java.util.Comparator

java.io.FileFilter

java.nio.file.PathMatcher

java.lang.reflect.InvocationHandler

java.beans.PropertyChangeListener

java.awt.event.ActionListener

javax.swing.event.ChangeListener

最后我们列举下java8中 java.util.function包下,内置所有的接口简介和表达的意思

1 BiConsumer<T,U>

代表了一个接受两个输入参数的操作,并且不返回任何结果:void accept(T t, U u);

2 BiFunction<T,U,R>

代表了一个接受两个输入参数的方法,并且返回一个结果

3 BinaryOperator<T>

代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果

4 BiPredicate<T,U>

代表了一个两个参数的boolean值方法

5 BooleanSupplier

代表了boolean值结果的提供方

6 Consumer<T>

代表了接受一个输入参数并且无返回的操作

7 DoubleBinaryOperator

代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。

8 DoubleConsumer

代表一个接受double值参数的操作,并且不返回结果。

9 DoubleFunction<R>

代表接受一个double值参数的方法,并且返回结果

10 DoublePredicate

代表一个拥有double值参数的boolean值方法

11 DoubleSupplier

代表一个double值结构的提供方

12 DoubleToIntFunction

接受一个double类型输入,返回一个int类型结果。

13 DoubleToLongFunction

接受一个double类型输入,返回一个long类型结果

14 DoubleUnaryOperator

接受一个参数同为类型double,返回值类型也为double 。

15 Function<T,R>

接受一个输入参数,返回一个结果。

16 IntBinaryOperator

接受两个参数同为类型int,返回值类型也为int 。

17 IntConsumer

接受一个int类型的输入参数,无返回值 。

18 IntFunction<R>

接受一个int类型输入参数,返回一个结果 。

19 IntPredicate

接受一个int输入参数,返回一个布尔值的结果。

20 IntSupplier

无参数,返回一个int类型结果。

21 IntToDoubleFunction

接受一个int类型输入,返回一个double类型结果 。

22 IntToLongFunction

接受一个int类型输入,返回一个long类型结果。

23 IntUnaryOperator

接受一个参数同为类型int,返回值类型也为int 。

24 LongBinaryOperator

接受两个参数同为类型long,返回值类型也为long。

25 LongConsumer

接受一个long类型的输入参数,无返回值。

26 LongFunction<R>

接受一个long类型输入参数,返回一个结果。

27 LongPredicate

R接受一个long输入参数,返回一个布尔值类型结果。

28 LongSupplier

无参数,返回一个结果long类型的值。

29 LongToDoubleFunction

接受一个long类型输入,返回一个double类型结果。

30 LongToIntFunction

接受一个long类型输入,返回一个int类型结果。

31 LongUnaryOperator

接受一个参数同为类型long,返回值类型也为long。

32 ObjDoubleConsumer<T>

接受一个object类型和一个double类型的输入参数,无返回值。

33 ObjIntConsumer<T>

接受一个object类型和一个int类型的输入参数,无返回值。

34 ObjLongConsumer<T>

接受一个object类型和一个long类型的输入参数,无返回值。

35 Predicate<T>

接受一个输入参数,返回一个布尔值结果。

36 Supplier<T>

无参数,返回一个结果。

37 ToDoubleBiFunction<T,U>

接受两个输入参数,返回一个double类型结果

38 ToDoubleFunction<T>

接受一个输入参数,返回一个double类型结果

39 ToIntBiFunction<T,U>

接受两个输入参数,返回一个int类型结果。

40 ToIntFunction<T>

接受一个输入参数,返回一个int类型结果。

41 ToLongBiFunction<T,U>

接受两个输入参数,返回一个long类型结果。

42 ToLongFunction<T>

接受一个输入参数,返回一个long类型结果。

43、UnaryOperator<T>

接受一个参数为类型T,返回值类型也为T。

如果更好的使用上面的方法,我们就需要引入stream,基本上实现了Collection的接口的如:Set,List,Map,SortedSet都可以得到stream


stream的方法:

可以分成两种类型,一种返回类型为接口本身的Stream<T>,另外一种是返回其他对象类型的,返回接口类型的,我们称这些方法为

中间操作

,返回其他具体类型的,我们称为

终端操作



中间操作

,调用stream的方法后返回对象本身就叫中间操作比如StringBuilder类的append方法,调用后返回的还是StringBuilder对象。


终端操作

,是指返回最终的结果,我们常用的forEach内部迭代

———————–中间操作———————–

//map操作
Stream<R> map(Function<? super T, ? extends R> mapper);

//filter操作
Stream<T> filter(Predicate<? super T> predicate);

//flatMap操作
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

//去重复
Stream<T> distinct();

//排序,默认顺序排
Stream<T> sorted();

//根据属性排序
Stream<T> sorted(Comparator<? super T> comparator);

//对对象的本身进行操作,比如在遍历的同时,在修改他某个属性的值。这个和forEach有点类似,但是这个是有返回的值的会得到一个新的stream。
Stream<T> peek(Consumer<? super T> action);

//截断--取先maxSize个对象
Stream<T> limit(long maxSize);

//截断--忽略前N个对象
Stream<T> skip(long n);

———————–终端操作———————–

返回Optional类型。

Optional<T> min(Comparator<? super T> comparator);  
Optional<T> max(Comparator<? super T> comparator);
Optional<T> findFirst();  
Optional<T> findAny();


findFirst和findAny,通过名字,就可以看到,对这个集合的流,做一系列的中间操作后,可以调用findFirst,返回集合的第一个对象,

findAny返回这个集合中,取到的任何一个对象;通过这样的描述,我们也可以知道,在串行的流中,findAny和findFirst返回的,

都是第一个对象;而在并行的流中,findAny返回的是最快处理完的那个线程的数据,所以说,在并行操作中,对数据没有顺序上的要求,那么findAny的效率会比findFirst要快的

void forEach(Consumer<? super T> action); 不按顺序处理,效率比forEachOrdered高
void forEachOrdered(Consumer<? super T> action); 按顺序处理stream
long count();  
boolean anyMatch(Predicate<? super T> predicate);anyMatch表示,判断的条件里,任意一个元素成功,返回true
boolean allMatch(Predicate<? super T> predicate);allMatch表示,判断条件里的元素,所有的都是,返回true
boolean noneMatch(Predicate<? super T> predicate);noneMatch跟allMatch相反,判断条件里的元素,所有的都不是,返回true

———————–collect操作———————–

// 转list
List<String> names = list.stream().map(emp -> emp.getName()).collect(Collectors.toList());
// 转set
Set<String> address = list.stream().map(emp -> emp.getName()).collect(Collectors.toSet());
// 转map,需要指定key和value,Function.identity()表示当前的Emp对象本身
Map<String, Emp> map = list.stream().collect(Collectors.toMap(Emp::getName, Function.identity()));
// 计算元素中的个数
Long count = list.stream().collect(Collectors.counting());
// 数据求和 summingInt summingLong,summingDouble
Integer sumAges = list.stream().collect(Collectors.summingInt(Emp::getAge));
// 平均值 averagingInt,averagingDouble,averagingLong
Double aveAges = list.stream().collect(Collectors.averagingInt(Emp::getAge));

// 综合处理的,求最大值,最小值,平均值,求和操作
// summarizingInt,summarizingLong,summarizingDouble
IntSummaryStatistics intSummary = list.stream().collect(Collectors.summarizingInt(Emp::getAge));
System.out.println(intSummary.getAverage());// 19.5
System.out.println(intSummary.getMax());// 22
System.out.println(intSummary.getMin());// 17
System.out.println(intSummary.getSum());// 117

// 连接字符串,当然也可以使用重载的方法,加上一些前缀,后缀和中间分隔符
String strEmp = list.stream().map(emp -> emp.getName()).collect(Collectors.joining());
String strEmp1 = list.stream().map(emp -> emp.getName()).collect(Collectors.joining("-中间的分隔符-"));
String strEmp2 = list.stream().map(emp -> emp.getName()).collect(Collectors.joining("-中间的分隔符-", "前缀*", "&后缀"));
最大值
Optional<Integer> maxAge = list.stream().map(emp -> emp.getAge()).collect(Collectors.maxBy(Comparator.comparing(Function.identity())));
// 最小值
Optional<Integer> minAge = list.stream().map(emp -> emp.getAge()).collect(Collectors.minBy(Comparator.comparing(Function.identity())));


// 归约操作

list.stream().map(emp -> emp.getAge()).collect(Collectors.reducing((x, y) -> x + y));
list.stream().map(emp -> emp.getAge()).collect(Collectors.reducing(0, (x, y) -> x + y));
// 分操作 groupingBy 根据地址,把原list进行分组
Map<String, List<Emp>> mapGroup = list.stream().collect(Collectors.groupingBy(Emp::getAddress));
// partitioningBy 分区操作 需要根据类型指定判断分区
Map<Boolean, List<Integer>> partitioningMap = list.stream().map(emp -> emp.getAge()).collect(Collectors.partitioningBy(emp -> emp > 20));