Java8 Lambda、Stream

Lambda表达式

        必须依赖函数式接口!
        函数式接口(@FunctionalInterface):    一个接口只声明一个抽象方法

左边   接口中的抽象方法的形参列表
右边   重写的抽象方法的方法体

使用:

1、无参无返回值

接口 t1 = () -> { 语句; } ;

 2、有参无返回值

接口 t2 = (参数类型  参数名) -> { 语句; } ;

3、参数类型可推断(使用泛型限定或者参数已经被限定)

接口<参数类型> t3 = (参数名) ->{ 语句; } ;
接口 t3 = (参数名) ->{ 语句; } ;

4、只需要一个参数

接口<类型> t4 = 参数名 ->{ 语句; } ;

5、两个以上参数,有返回值

接口<类型> t5 = (参数名1,参数名2) -> { 语句;  return 返回值; } ;

6、只有一条语句,return和大括号都可省略

接口 t6 = (参数名...)-> 返回值 ; 

Sub sub =(a,b)->  a-b  ;

总结:  

左边一个参数可以省略小括号;

右边只有一条执行语句(包括renturn语句)可以省略大括号(和return关键字)

本质:

        作为接口的实例(实现类的对象),简化匿名函数实现过程

 

四大核心函数式接口:

 函数式接口参数类型返回类型用途
 Consumer<T>voidvoid accept(T t);    输入数据

 

consumerFunction(12, new Consumer<Integer>() {
    @Override
    public void accept(Integer t) {
        System.out.println("hhh:"+t);
    }
} );
public static void consumerFunction(int age,Consumer<Integer> cons){
    cons.accept(age);
}

 

Supplier<T>T T get();        获得数据
//创建Supplier容器,声明为TestSupplier类型,此时并不会调用对象的构造方法,即不会创建对象
Supplier<User> supplier = () ->  new User();
//调用get()方法,此时会调用对象的构造方法,即获得到真正对象 即懒加载
System.out.println(supplier.get());;

 

Function<T,R>TR R  apply(T t);    处理数据
Function<String,User> function = User::new ;
function.apply("hello");

//此时User对象的构造方法应该有如下
public User(String name){this.name = name;	}

 

Predicate<T>Tbooleanboolean test(T t);   判断是否满足约束
//匿名内部类创建
ArrayList<String>  res = consumerFunction(list,new Predicate<String>() {
    @Override
    public boolean test(String t) {
        return t.length()>2;
    }
});

//Lambda表达式
ArrayList<String>   res = consumerFunction(list, (name)->{
    return name.length()>2;
});

//最简洁版本
ArrayList<String>   res = consumerFunction(list, (name)->  name.length()>2 );


public static ArrayList<String>  consumerFunction(List<String> list,Predicate<String> pre){
    ArrayList<String> filterList = new ArrayList<>();
    for(String s : list){
        if(pre.test(s)){
            filterList.add(s);
        }
    }
    return filterList;
}

 

其他函数式方法

方法引用

1、使用情景:当要传递给Lambda体的操作,已经有实现的方法可以使用

2、方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。

3、使用格式:      类(或对象) :: 方法名

情况一、对象 ::非静态方法

//Consumer中的void  accept(T t) 与  System.out中的 void println(T t);
Consumer<String> con = str -> System.out.println(str);

//方法引用
Consumer<String> con1 = System.out::println; 

情况二、类 ::静态方法

举例一:
Comparator中的 int compare(T t1,T t2)与Integer中的int compare(T t1,T t2)
Comparator<Integer> com1 =(a,b)->Integer.compare(a, b);
System.out.println( com1.compare(2, 4));
Comparator<Integer> com2 = Integer::compare;
System.out.println( com2.compare(4, 2));

举例二:
Function中的R apply(T t) 与Math中的Long round(Double d)
Function<DOuble,Long> func = d -> Math.round(d);
Function<DOuble,Long> func = Math::round;
func.apply(12.6);

            (使用要求:接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同)

 

情况三、 类::非静态方法  (参数一做了方法的调用者)

举例一:
Comparator 中的int comapre(T t1,T t2) 与 String 中的int t1. compareTo(t2)
Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
System.out.print1n( com1. compare("abc", "abd"));
Comparator<String> com2 = String :: compareTo;
System.out.print1n( com2.compare("abd", "abm"));
注意:对象的get方法也可以使用
BiPredicate中的boolean test(T t1。T t2); 与 string中的boolean t1. equols(t2)

构造器引用

格式:ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容 ,可以把构造器引用赋值给定义的方法

要求:构造器参数列表要与接口中抽象   方法的参数列表一致!且方法的返回值即为构造器对应类的对象。

构造器引用
//构造器与函数式接口的抽象方法形参列表和返回值类型一致 可以简写
BiFunction<Integer,String,User> biFunction = (id,name) -> new User(id, name);
User user = biFunction.apply(1, "hello");
BiFunction<Integer,String,User> biConsumer2 = User::new;
User user2 = biConsumer2.apply(2, "abcd");

 

数组引用

看成特殊的类,类似与构造器引用   格式:   type[] :: new

Stream流

对集合数据进行操作

Stram和Collection集合区别:
       Collection是一种静态的内存数据结构 ,面向内存
       Stream是有关计算的 , 面向CPU 通过CPU实现计算

注意:

  • Stream自己不会存储元素。
  • Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

操作三个步骤

  • 创建Stream
  • 中间操作 (   操作链  延时(终止前不执行))
  • 终止操作(终端操作)

创建方式

  • 通过集合
List<Integer> list = new ArrayList<>();
Stream<Integer> stream = list.stream();
  • 通过数组
int[] listarr = {1,2,3,4,};
IntStream stream = Arrays.stream(listarr);
  • 通过Stream的of()
Stream<List<Integer>> stream3 = Stream.of(list);
  • 迭代
Stream.iterate( 种子数,UnaryOperator<T> f )  
不停迭代   需要limit中间操作 结束  否则无限迭代

Stream.generate()    产生

操作方法

筛选与操作

filter(Predicate p)   接受Lamba   从流中排除某些元素
users.stream().filter(x->x.id<3).forEach(System.out::println); 

//练习 集合 交并补差
List<Integer> Alist = Arrays.asList(1,23,35,67,83,3);
List<Integer> Blist = Arrays.asList(1,3,4,5);

List<Integer> innerJoin = Alist.stream().filter(Blist::contains).collect(Collectors.toList());

List<Integer> aSubB = Alist.stream().filter(item -> !Blist.contains(item)).collect(Collectors.toList());

List<Integer> bSubA = Blist.stream().filter(item -> !Alist.contains(item) ).collect(Collectors.toList());

List<Integer> aPlusB = new ArrayList<>();
aPlusB.addAll(Alist);
aPlusB.addAll(Blist);

aPlusB = aPlusB.stream().distinct().collect(Collectors.toList());
List<Integer> subInner = new ArrayList<>();
subInner.addAll(bSubA);
subInner.addAll(aSubB);


limit( n )  截断流   元素不超过给定元素

skip( n )   跳过前n个数据  不满n个 则返回一个空的

distinct()  筛选  通过流所生成元素的hashCode()和equals() 去除重复元素

映射

map(Function f)   接受一个函数作为参数 ,转换为其他形式或提取信息 ,函数会被应用到每个元素上,将其映射位一个新的元素
mapToDouble(ToDoubleFunction f)       接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream 。
mapToInt(ToIntFunction f)            接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream 。
mapToLong(ToLongFunction f)     接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream 。

flatMap(Function f)               接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

flat是扁平的意思。它把数组流中的每一个值,使用所提供的函数执行一遍,一一对应。得到元素相同的数组流。只不过,里面的元素也是一个子数组流。把这些子数组合并成一个数组以后,元素个数大概率会和原数组流的个数不同。

// 实例1:将集合中的字符串中单词提取出来,不考虑特殊字符
List<String> wordss = Arrays.asList("hello c++","hello java","hello python");
Stream<String[]> map = wordss.stream().map(word -> word.split(" "));
// 将单词按照空格切合,返回Stream<String[]>类型的数据
// 将Stream<String[]>转换为Stream<String> 
List<String> collect = map.flatMap(Arrays::stream).distinct().collect(Collectors.toList());// 去重

 
//实例
Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
characterStream.forEach(System.out::println);

//将字符串中的多个字符构成的集合转换为对应的Stream的实例
public static Stream<Character> fromStringToStream(String str){//aa
    ArrayList<Character> list = new ArrayList<>();
    for(Character c : str.toCharArray()){
        list.add(c);
    }
    return list.stream();
}

收集

collect(Collector c)     将流转换为其他形式。接收一个Collector 接口的实现,用于给 Stream 中元素做汇总的方法

方法返回类型作用
toListList<T>把流中元素收集到List
List<Employee>   emps = list.stream.collect(Collectors.toList())
toSetSet<T>把流中元素收集到Set
Set<Employee> emps = list.stream.collect(Collectors.toSet())
toCollectionCollection<T>把流中元素收集到创建的集合
Collection<Employee> emps =list.stream().collect(Collectors.toCollection(ArrayList::new));
countingLong计算流中元素的个数
long count = list.stream().collect(Collectors.counting());
summingIntInteger对流中元素的整数属性求和
int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingIntDouble计算流中元素Integer 属性的平均值
double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingIntIntSummaryStatistics收集流中Integer 属性的统计值 。 如:平均值
int SummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joiningString连接流中每个字符串
String str= list.stream().map(Employee::getName).collect(Collectors.joining());
maxByOptional<T>根据比较器选择最大值

Optional<Emp>max=
                list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));

minByOptional<T>根据比较器选择最小值

Optional<Emp> min =
                 list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));

reducing归约产生的类型从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值
int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));

collectingAndThen

转换函数返回的类型

包裹另一个收集器,对其结果转换函数

int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingByMap<K, List<T>>根据某属性值对流分组,属性为K,结果为V
Map<Emp.Status, List<Emp>> map=
                list.stream().collect(Collectors.groupingBy(Employee::getStatus));
partitioningByMap<Boolean, List<T>>根据true或false进行分区
Map<Boolean,List<Emp>> vd =
               list.stream().collect(Collectors.partitioningBy(Employee::getManage));

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值