/** * 符合lambda表达式的接口也叫函数式接口: * 除了默认方法和Object类的方法外,只有一个抽象方法的接口才能符合lambda表达式的要求 * 可以使用@FunctionalInterface来校验,如果没报错就是符合要求的 * * */ @FunctionalInterface public interface Animal { default String getName(){ return "animal"; } void eat(); } //无参有返回 public interface Person { String getName(); } //有参无返回 public interface Sckool { void learn(String name); } //有参有返回 public interface Student { String conCat(String str,String str2); } package lambda; public class testLambda { public static void main(String[] args) { //要调用一个接口的方法,要么定义一个类来实现该接口,要么使用匿名内部类: //下面使用匿名内部类: eat(new Animal() { @Override public void eat() { System.out.println("动物吃东西"); } }); /** * 如果匿名内部类只有一个方法,可以使用lambda表达式替换: * 总共分下面4种情况: * 无参无返回格式: * 单条语句时()->xxx ;多条语句时()->{xx;aa;} * 无参有返回: * 单条语句时()->xxx;多条语句时()->{xx; return aa;} * 有参无返回: * 单条语句单个参数时:a->xxx;多条语句单个参数时a->{xx;cc;} * 单条语句多个参数时:(a,b)->xxx;多条语句多个参数时(a,b)->{xx;cc;} * * 有参有返回: * 单条语句单个参数时:a->xxx;多条语句单个参数时a->{xx;return cc;} * 单条语句多个参数时:(a,b)->xxx;多条语句多个参数时(a,b)->{xx; return cc;} */ //-------- 无参无返回格式: //单条语句时()->xxx eat(()-> System.out.println("aaa")); //多条语句时()->{xx;aa;} eat(()->{ System.out.println("dd"); System.out.println("cc"); }); //---------无参数有返回格式: // 单条语句时()->xxx; String name=getName(()->"kk"); //多条语句时()->{xx; return aa;} getName(()->{ System.out.println("dd"); return "cc"; }); //--------有参数无返回时 //单条语句单个参数时 learn(a-> System.out.println(a)); //多条语句单个参数时a->{xx;cc;} learn(a->{ System.out.println("lll"); System.out.println("cc"); }); //单条语句多个参数时 // learn((a,b)-> System.out.println(a+b)); //多条语句多个参数时(a,b)->{xx;cc;} /** * * learn((a,b)-> { System.out.println("lll"); System.out.println("cc"); }); * */ //---------有参数有返回 //单条语句单个参数时:a->xxx; // learn(a-> "dd"); //多条语句单个参数时a->{xx;return cc;} /** * learn(a->{ System.out.println("lll"); return "ss"; }); * * */ //单条语句多个参数时:(a,b)->xxx String subject=concat((a,b)->a+b); //多条语句多个参数时(a,b)->{xx; return cc;} String subject2=concat((a,b)->{ System.out.println("ddd"); return a+b; }); /** * * 我们使用lambda表达式时候,都是要实现一个方法,如果你要实现的方法刚好其他类有,那么就可以引用其他类的方法过来当做该匿名内部类的实现 * 所以方法的引用分为: * 静态方法的引用,如System.out:println * 非静态方法的引用:如 new Dog()::eat; * 参数类型方法的引用,例如一个要实现的方法参数是String a,String b ,期望的结果是a+b,那么可以引用String::concat方法 * * */ learn(System.out::print); //刚好learn的内部类要实现的方法跟System.out的方法长得一样,所以可以引用该方法当做自己的实现方法 eat(new testLambda()::haveMeal);//非静态方法的引用 String str=concat(String::concat);//参数 System.out.println(str); } public static void eat(Animal animal){ animal.eat(); } public static String getName(Person person){ return person.getName(); } public static void learn(Sckool sckool){ sckool.learn("java"); } public static String concat(Student student){ return student.conCat("java","php"); } public void haveMeal(){ System.out.println("吃饭"); } }
//stream 流:
package lambda; import java.math.BigDecimal; public class Cat { private String name; private BigDecimal price; public Cat(String name, BigDecimal price) { this.name = name; this.price = price; } @Override public String toString() { return "Cat{" + "name='" + name + '\'' + ", price=" + price + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } } package lambda; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class testLambda { public static void main(String[] args) { List<Cat> list=new ArrayList<>(); list.add(new Cat("k",new BigDecimal("200"))); list.add(new Cat("g",new BigDecimal("100"))); list.add(new Cat("k",new BigDecimal("300"))); list.add(new Cat("l",new BigDecimal("400"))); list.add(new Cat("b",new BigDecimal("500"))); list.add(new Cat("b",new BigDecimal("501"))); /** * Stream流:跟IO的流是不一样的,比较适当的比喻可以当做一个管道,数据从管道一端流经另一端,中间会经过多个操作,如过滤,排序 * * 流程: 源 ------过滤----排序---终止-结果 * * 所有操作分为三类 * 1.创建流 * 2.中间操作(惰性操作) : 凡是返回值类型是Stream的都是中间操作,如果只有中间操作,没有终止操作,流是不会执行的 * 3.终值操作 * * * * 创建: * Collection.stream(); * Arrays.asList("a","b").stream(); * Stream.of("a","b"); * */ /** * 流的特点: * 1.不能重复使用,每经过一个中间操作都返回新的流,之前的流就关闭了 * 2.最多只能有一个终值操作,并且终值操作都是在最后 * 3.执行顺序: * 假如一个流经过 filter--sorted操作,顺序是一个元素先经过filter--sorted 然后下一个元素经过filter--sorted,并不是所有元素先经过filter,然后经过sorted * * */ Stream<Cat> stream = list.stream(); //过滤操作是中间操作,如果没有终值操作就不会执行 Stream<Cat> stream2 = stream.filter(a -> { System.out.println("中间操作是惰性的,这句话不会输出"); return a.getName().equals("b"); }); //下面的操作会报错:java.lang.IllegalStateException: stream has already been operated upon or closed //因为stream在上一步执行完filter就关闭了 /*stream.filter(a-> { System.out.println("流不能重复使用"); return a.getName().equals("b"); }).toArray();*/ Object[] bs = stream2.filter(a -> { System.out.println("有终值操作toArray,所以该方法会被执行"); return a.getName().equals("b"); }).toArray(); //测试流是一个一个执行元素还是全部一起执行 list.stream().filter(a->{ System.out.println("过滤操作"); return !a.getName().equals("oo"); }).forEach(a-> System.out.println("遍历操作")); //输出结果: 过滤操作 遍历操作 过滤操作 遍历操作 ..... //常用的Strem API //过滤filter:上面的例子 System.out.println(Arrays.toString(bs)); //peek 和 forEach操作,peek不是终值操作,执行后还能继续执行其他中间操作,forEach是终值操作 list.stream().peek(System.out::println); //不会打印数据,因为中间操作是懒惰的 list.stream().peek(System.out::println).toArray(); list.stream().forEach(System.out::println);//终值操作,直接会输出结果 //map 将元素按照一定规则映射成另外一个元素 List<String> nameList = list.stream().map(a -> a.getName()).collect(Collectors.toList()); System.out.println(nameList); //distinct 去重 List<String> distionctNameList = list.stream().map(a -> a.getName()).distinct().collect(Collectors.toList()); System.out.println(distionctNameList); //sorted 排序 List<Cat> sortList = list.stream().sorted((a, b) -> b.getPrice().compareTo(a.getPrice())).collect(Collectors.toList()); System.out.println(sortList); //limit 操作 List<Cat> limitList = list.stream().limit(2).collect(Collectors.toList()); System.out.println(limitList); //mapToInt和reuduce用户sum()操作时,调用int reduce(int identity, IntBinaryOperator op);所有元素op操作后加上identity的值就得到sum()的值了 int reduce = list.stream().mapToInt(a -> a.getPrice().intValue()).reduce(0, (a, b) -> a + b); //2001 int reduce2 = list.stream().mapToInt(a -> a.getPrice().intValue()).reduce(-1, (a, b) -> a + b);//2000 int reduce3 = list.stream().mapToInt(a -> a.getPrice().intValue()).reduce(20, (a, b) -> a + b);//2021 System.out.println(reduce); System.out.println(reduce2); System.out.println(reduce3);
//BigDecimal payAmount = billMastList.stream().map(a -> a.getAmtBillPayment()).reduce(BigDecimal.ZERO, BigDecimal::add); 金额处理 //skip操作 跳过多少个元素,从1开始算 List<Cat> skipList = list.stream().skip(1).collect(Collectors.toList()); System.out.println(skipList); //价格最贵的 max(Comparator<? super T> comparator) Cat cat = list.stream().max((a, b) -> a.getPrice().compareTo(b.getPrice())).get(); System.out.println(cat); // boolean anyMatch(Predicate<? super T> predicate),判断是否有比600价格贵的 boolean b = list.stream().allMatch(a -> a.getPrice().compareTo(new BigDecimal(600)) > 0); boolean b2 = list.stream().anyMatch(a -> a.getPrice().compareTo(new BigDecimal(500)) > 0); System.out.println(b); System.out.println(b2); //findAny() 获取任意一个 Cat cat1 = list.stream().findAny().get(); System.out.println(cat1); //findFirst() 获取第一个 Cat cat2 = list.stream().findFirst().get(); System.out.println(cat2); //flatMap:比较像降维打击,如三维空间变成二维空间,具体的意思是每个元素经过处理,生成新的流.例如这里每个cat获取它的名字组成一个新的集合 //再举个例子,订单跟商品,一个订单集合经过flatMap,获取每个订单的商品集合组成一个新的流 List<String> flatMapList = list.stream().flatMap(a -> Stream.of(a.getName())).collect(Collectors.toList()); System.out.println(flatMapList);
//list转map 第一个参数是key值,第二个参数value值,第三个参数是key重复时,value如何进行合并
Map<String, BigDecimal> map = list.stream().collect(Collectors.toMap(a -> a.getName(), a -> a.getPrice(),(c, d)->c.add(d)));
System.out.println(map);
//分组功能
List<PerSon> list=new ArrayList<>();
list.add(new PerSon("yang",12));
list.add(new PerSon("yang",20));
list.add(new PerSon("ming",12));
list.add(new PerSon("ming",362));
list.add(new PerSon("tt",12));
list.add(new PerSon("kk",12));
Map<String, List<PerSon>> collect = list.stream().collect(Collectors.groupingBy(PerSon::getName)); //会分成四组,根据名字来分组
//注意 list转map如果value值为null会报,如果key重复,不处理也会报错,处理最好如下所示
custmerNameMap = customerInfoBatchList.stream().filter(a->StringUtils.isNotBlank(a.getCustomerName())) //过滤空值
.collect(Collectors.toMap(XfaceCustomerInfoListForBatchResponseSubDTO::getCustomerId, XfaceCustomerInfoListForBatchResponseSubDTO::getCustomerName,(k1,k2)->k1)); //
(k1,k2)->k1)代表key重复时,取第一个
//总结:所有API都不用记!!要用任何一个方法,点开Stream类可以查看到,或者idea工具提示可以找到任何一个方法,每个方法的参数都是一个接口,找到该接口看看其要实现的方法,然后使用lambda表达式就可以了 } }
idea安装插件可以对stream流进行debug: