lambda表达式-2021-5-16

最近又找了个lambda表达式的课程,来记录下笔记

一.lambda表达式

好处是不用写参数的类型

1.等号左边是接口,等号右边是实现

 Itest itest = (s1, s2) -> {
            System.out.println("sssss");
            return "123";
        };

 System.out.println(itest.test("s1","s2"));

2.最经典的Runnable写法

        //改lambda前
        Thread test = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("test");
            }
        });
        test.start();
        //改lambda后
        Thread testLambda = new Thread(() -> System.out.println("test"));
        testLambda.start();

3.各种测试代码

        System.out.println(itest.test("s1","s2"));*/
        Comparator<Integer> comparator = Comparator.comparingInt(o -> o);
        List<Integer> list = new ArrayList<>();
        list.add(9);
        list.add(3);
        list.add(4);
        list.stream().forEach(System.out::println);
        System.out.println("------------------------------");
        //filter过滤
        list.stream().filter(integer -> integer>4).forEach(System.out::println);
		
		lombok的@ToString注解
		TestEntity(i=1, j=2)
		
		
		TestEntity testEntity1 = new TestEntity(1,2);
        TestEntity testEntity2 = new TestEntity(3,4);
        //快速拼数组
        List<TestEntity> testEntities = Arrays.asList(testEntity1, testEntity2);
        testEntities.stream().forEach(System.err::println);
		
		输出
		TestEntity(i=1, j=2)
		TestEntity(i=3, j=4)

4.插播一个@ToString注解

二.四大核心函数

四大函数  可以看到 他们都是泛型

1.消费型接口

消费型是需要入参的 但是没有返回 我给你什么 你把他给我消费  比如我们用foreach方法时就会用到消费型接口

 Consumer<String> consumer = System.out::println;

2.供给型接口

供给型是没有入参的 但是有返回  返回什么拿什么 而不是你再上传给我

 Supplier<Integer> supplier = () -> 100;

3.函数型接口

函数型接口很常用,有上传T 也有返回R   比如我们用map方法时就会用到函数式接口  flatmap时也会用函数式接口

Function<String, Integer> function = s -> Integer.valueOf(s) + 100;//就一行代码 不用写return  也不用大括号{}
System.out.println(function.apply("10"));

4.断言型接口

断言型接口  有上传  返回是Boolean  比如我们用filter方法时就会用到断言型接口

Predicate<Integer> predicate = integer -> {//多行代码 需要大括号{} return也不能省
            if(integer==2){
                return true;
            }else{
                return false;
            }
        };

三.创建stream的方式

1.对stream的操作有这样几步

1.1.创建流

1.2.操作流

1.3.终止流

2.创建流的几种方式

1.集合转换为流 

最常用

list.stream()

List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
Stream<String> stream1 = list.stream();
stream1.forEach(System.out::println);

2.数组转换为流

Arrays.stream()

    String[] strArr =  new String[2];
	strArr[0] = "3";
	strArr[1] = "4";
	Stream<String> stream2 = Arrays.stream(strArr);
	stream2.forEach(System.out::println);

3.流的静态方法

Stream.of(1,2,3)

Stream<Integer> stream3 = Stream.of(5,6);
stream3.forEach(System.out::println);

4.创建一个没有限制的流

项目里还没看谁用过

Stream<Integer> stream4 = Stream.iterate(0, integer -> integer + 1);
stream4.forEach(System.out::println);//这里会一直打印 除非强制停止

四.flatMap

把几个小的list转换到一个大的list

可参考链接:java8 map flatmap - 穆穆兔兔 - 博客园

        List<Integer> list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);
        List<Integer> list2 = new ArrayList<>();
        list2.add(3);
        list2.add(4);
        List<Integer> list3 = new ArrayList<>();
        list3.add(5);
        list3.add(6);
        List<List<Integer>> bigList = new ArrayList<>();
        bigList.add(list1);
        bigList.add(list2);
        bigList.add(list3);
        //flatmap  大list转为小list
        //以下三种处理方式是一个效果 都是打印出了123456
        List<Integer> collect1 = bigList.stream().flatMap(Collection::stream).collect(Collectors.toList());
        collect1.forEach(System.out::println);
        System.out.println("----------------------------------------------------");
        List<Integer> collect2 = bigList.stream().flatMap(everyList -> everyList.stream()).collect(Collectors.toList());
        collect2.forEach(System.out::println);
        System.out.println("----------------------------------------------------");
        List<Integer> collect3 = bigList.stream().flatMap((Function<List<Integer>, Stream<Integer>>) integers -> integers.stream()).collect(Collectors.toList());
        collect3.forEach(System.out::println);

五.多属性排序

5.1thenComparing

        List<Person> people = Arrays.asList(
                //字符串比较是按照字母顺序一个一个比较
                new Person(3, "bbc"), new Person(3, "caa"),
                new Person(5, "55"), new Person(6, "66"),
                new Person(1, "11"), new Person(2, "22")
        );
        //如果年龄相同  就按照姓名排序
        //以下两种写法输出一样
        //第一种写法
        people.stream().sorted((o1, o2) -> {
            if(o1.getAge()-o2.getAge()==0){
                return o1.getName().compareTo(o2.getName());
            }else{
                return o1.getAge()-o2.getAge();
            }
        }).forEach(System.out::println);
       //第二种写法
        System.out.println("---------------------------------------");
        //多属性排序   也和sql查询相同  当第一个排序字段重复时候  第二个排序字段才会生效
         people.stream().sorted(
                Comparator.comparing(Person::getAge)
                        .thenComparing(Person::getName)
        ).forEach(System.out::println);

5.2注意compare不会改变原来的值

    @AllArgsConstructor
    @Getter
    @ToString
    public static class A{
        int a;
        int b;
        int c;
    }

    public static void main(String[] args) {
        List<A> as = Arrays.asList(new A(1, 9, 3), new A(1, 5, 6), new A(1, 2, 9));
        //compare不会改变原来的值,要新写一个返回
        List<A> collect = as.stream().sorted(Comparator.comparing(A::getA).thenComparing(A::getB).thenComparing(A::getC)).collect(Collectors.toList());
        //输出新的返回值,是按照比较大小排列的
        collect.forEach(System.out::println);
        System.out.println("----------------------------------------------------");
        //输出原来的数组,还是按照原来的方式排列的
        as.forEach(System.out::println);
    }

 5.2.1运行结果

5.3引申到foreach是否会在循环中改变原list的值

foreach其实就是一个for循环嘛,for循环中能改变的东西,foreach中也能改变 

六.收集到指定容器中

Collectors.toCollection

List<Person> people = Arrays.asList(
			//字符串比较是按照字母顺序一个一个比较
			new Person(3, "bbc"), new Person(3, "caa"),
			new Person(5, "55"), new Person(6, "66"),
			new Person(1, "11"), new Person(2, "66")
	);
people.stream().map(Person::getName).collect(Collectors.toList()).forEach(System.out::println);
System.out.println("----------------------------------------------------------------");
//去重
people.stream().map(Person::getName).collect(Collectors.toSet()).forEach(System.out::println);
System.out.println("******************************************************************");
//收集到指定的容器中
people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new)).forEach(System.out::println);

七.计算

1.求平均值

Collectors.averagingInt

//求平均值
Double collect = people.stream().collect(Collectors.averagingInt(Person::getAge));

2.其他

//最大值
people.stream().max(Comparator.comparingInt(Person::getAge)).ifPresent(person -> System.out.println("max:"+person.getAge()));
//最小值
people.stream().min(Comparator.comparingInt(Person::getAge)).ifPresent(person -> System.out.println("min:"+person.getAge()));
//个数
System.out.println("count:"+people.stream().count());
//和
people.stream().reduce((person, person2) -> new Person(person.getAge()+person2.getAge(),"sum"))
		.ifPresent(person -> System.out.println("sum:"+person.getAge()));
//和
as.stream().map(A::getA).reduce(Integer::sum).ifPresent(integer -> System.out.println("reduceA  "+integer));

//平均值
System.out.println("avg:"+people.stream().collect(Collectors.averagingInt(Person::getAge)));

综上可见  .collect方法都要用到Collectos工具类

八.collectingAndThen对处理过后的stream再次处理

这个有难度

注意 Collectors.collectingAndThen是包含在Collectors.groupingBy里边的  并且是在分组之后的

1.Collectors.collectingAndThen一般以Collectors.toList()作为第一个入参

在idea中的写法,就是先Collectors.collectingAndThen()

然后第一个入参 Collectors.toList() 第二个入参 new 空格 回车就自动出现实现的函数了

2.分组后的数据  以sex为key  以分组得到的name集合为value

Map<String, List<String>> collect = people.stream().collect(Collectors.groupingBy(PersonWithSex::getSex,
		Collectors.collectingAndThen(Collectors.toList(),
				personWithSexes -> personWithSexes.stream().map(PersonWithSex::getName)
						.collect(Collectors.toList()))));

3.分组后的数据 以sex为key  以对应的age和为value

Map<String, Integer> collect1 = people.stream().collect
			(
					Collectors.groupingBy
							(PersonWithSex::getSex, Collectors.collectingAndThen(Collectors.toList(),
									personWithSexes -> personWithSexes.stream().reduce
											((personWithSex, personWithSex2) ->
													new PersonWithSex(personWithSex.getAge() + personWithSex2.getAge(), "", "", 0))
											.get().getAge()))
			);

4.值得一看的博客

这位大佬对于CollectingAndThen 的解释很清晰,以下转自大佬博客

Collectors.collectingAndThen()_技匠而已的博客-CSDN博客_collectingandthen

Collectors.collectingAndThen() 函数应该最像 map and reduce 了,它可接受两个参数,第一个参数用于 reduce操作,而第二参数用于 map操作。

也就是,先把流中的所有元素传递给第一个参数,然后把生成的集合传递给第二个参数来处理。

例如下面的代码

把 [1,2,3,4] 这个集合传递给 v -> v * 2 lambda表达式,计算得出结果为[2,4,6,8]
然后再把 [2,4,6,8]传递给 Collectors.averagingLong 表达式,计算得出 5.0
然后传递给 s -> s * s lambda表达式,计算得到结果为 25.0

@Test
public void collectingAndThenExample() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4);
    Double result = list.stream().collect(Collectors.collectingAndThen(Collectors.averagingLong(v -> {
                System.out.println("v--" + v + "--> " + v * 2);
                return v * 2;
            }),
            s -> {
                System.out.println("s--" + s + "--> " + s * s);
                return s * s;
            }));
    System.out.println(result);
}

运行结果 

v--1--> 2
v--2--> 4
v--3--> 6
v--4--> 8
s--5.0--> 25.0
25.0

九.拼接

Collectors.joining

1.普通拼接

 String collect1 = people.stream().map(PersonWithSex::getName).collect(Collectors.joining());
        System.out.println(collect1);

2.指定分隔符拼接

//指定分隔符拼接
        String collect2 = people.stream().map(PersonWithSex::getName).collect(Collectors.joining(","));
        System.out.println(collect2);

3.指定分隔符和前后缀拼接

 //拼接时指定首位符号
        String collect3 = people.stream().map(PersonWithSex::getName).collect(Collectors.joining(",","start[","]end"));
        System.out.println(collect3);

4.数组转字符串经常用到

 List<A> as = Arrays.asList(new A(1, 9, 3), new A(1, 5, 6), new A(1, 2, 9));
 String collect = as.stream().map(a -> 
 String.valueOf(a.getB())).collect(Collectors.joining(","));
 System.out.println("Collectors.joining(\",\")"+collect);

//顺便说下字符串转数组
List<String> list = Arrays.stream(collect.split(",")).collect(Collectors.toList());

九.一段有文化的代码

1.返回实体

使用了@Bulider和@Data注解后,就可以使用链式风格优雅地创建对象

@Getter
@Setter
@Builder//重点就是这个@Builder注解
@AllArgsConstructor
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class SelectOption {

    String value;

    String name;

    String tips;
}

2.枚举类

@Getter
@AllArgsConstructor
public enum RecognitionEnum {

   
    TEST1("TEST1", "测试1"),

    
    TEST2("TEST2", "测试2"),

    
    TEST3("TEST3", "测试3");

    String value;

    String desc;
}

3.代码实现

    public List<SelectOption> recognitionTypeOption() {
        RecognitionType[] values = RecognitionEnum.values();//取出枚举数组
        return Arrays.stream(values)
                //通过map进行实体转换,从枚举实体转换为指定返回实体  这里用到.build链式赋值
                .map(recognitionType -> SelectOption.builder().name(recognitionType.getDesc()).value(recognitionType.getValue()).build())
                .collect(Collectors.toList());//最终转换为list返回
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值