Lambda表达式和Stream流

一、Lambda表达式

lambda表达式是jdk8中的新特性之一,对某些匿名内部类的写法进行了简化。将能省的东西都省掉了。
首先看一下我们原本创建线程常规写法应该怎么写
1.创建一个类去实现Runnable接口,重写run方法。
2.创建Thread对象,将实现了Runnable接口的对象作为Thread对象的参数
3.调用start方法启动线程,具体代码如下:

//创建实现Runnable的类
public class ThreadText implements Runnable{
    @Override
    public void run() {
        System.out.println("我是123 ");
    }
    public static void main(String[] args) {
        //创建实现Runnable接口类的对象
        ThreadText threadText=new ThreadText();
        //将此对象传作为参数创建Thread对象
        Thread thread=new Thread(threadText);
        //启动线程
        thread.start();
    }
}

img-blog.csdnimg.cn/902f90977785433cac9f1e0b69807c79.png
换一种写法,使用匿名内部类来实现

public class ThreadText {
    public static void main(String[] args) {
        //匿名内部类
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("我是456");
            }
        });
        thread.start();
    }
}

在这里插入图片描述
在换一种写法 ,使用Lambda表达式:

public class ThreadText {
    public static void main(String[] args) {
        //匿名内部类
        Thread thread=new Thread(()->{
            System.out.println("我是789 " );
        });
        thread.start();
    }
}

在这里插入图片描述
你会发现,是不是突然看不懂了,和匿名内部类相比,Lambda表达式有什么不同
在这里插入图片描述
可以看见,方框中的东西被胜率掉了,在使用Lambda表达式时,只关注方法的参数和方法体,其他的东西都可以省略。

1.1 什么情况下可以使用Lambda表达式

看看Runnable源码
在这里插入图片描述
一个接口里面,只有一个抽象方法,就可以在将该接口当做匿名内部类使用时,使用Lambda表达。

1.2 Lambda表达式的格式

  • (参数列表)->{代码}
  • Lambda表达式只关注参数列表和方法体,省略类名和方法的定义
  • 可以使用IDEA的快捷键 ALT+回车来进行匿名内部类和Lambda表达式的转换
    在这里插入图片描述

1.3 Lambda表达式的省略规则

  • 参数类型可以省略
  • 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
  • 方法只有一个参数时小括号可以省略

二、Stream流

2.1 创建流对象(Stream)

2.1.1单列集合

集合对象.stream()

    public static void main(String[] args) {
        ArrayList<Integer> list=new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        Stream<Integer> stream = list.stream();
        stream.filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer>2;
            }
        }).forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println("integer = " + integer);
            }
        });
    }
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.stream()
                .filter(integer -> {
                   return integer > 2;
                })
                .forEach(integer -> {
                    System.out.println("integer = " + integer);
                });
    }

在这里插入图片描述

2.1.2 数组

通过Arrays.stream(数组对象) 或者 Stream.of(数组对象)

    public static void main(String[] args) {
        Integer[] arr = {15, 16, 17, 20};
        //通过Arrarys.stream()
        Stream<Integer> stream = Arrays.stream(arr);
        stream.filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer > 17;
            }
        }).forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println("Arrarys.stream()创建的流,经过过滤之后的元素有:value = " + integer);
            }
        });
        //通过Stream.of
        Stream<Integer> streamOf = Stream.of(arr);
        streamOf.
                filter(id -> {
                    return id > 15;
                })
                .forEach(num -> {
                    System.out.println("Stream.of()创建的流,经过过滤之后的元素有:num = " + num);
                });
    }

在这里插入图片描述

2.1.3 双列集合

先将双列集合转换为单列集合

        HashMap<Object,Integer> map=new HashMap<>();
        map.put("张三",15);
        map.put("李四",16);
        //转换为单列集合
        Set<Map.Entry<Object, Integer>> entries = map.entrySet();
        Stream<Map.Entry<Object, Integer>> stream = entries.stream();
        stream.filter(p->{
            return p.getValue()>15;
        }).forEach(map1 -> {
            System.out.println(map1.getKey()+":++++++++++"+map1.getValue());
        });
        }

在这里插入图片描述

2.2 流对象的中间操作

2.2.1 filter

过滤,满足条件的元素才能继续留在流中,前面演示的代码已经体现了filter的作用。

2.2.2 map

将流中的元素进行计算或者转换,如果流是一个实体类,可以通过map给实体类中的某些属性赋值。
实体类

package com.example.demo.config;
import java.util.Objects;
public class User {
private String name;
private Integer age;
private String email;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Integer getEmail() {
        return email;
    }
    public void setEmail(Integer email) {
        this.email = email;
    }
    public User() {
    }
    public User(String name, Integer age, Integer email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return name.equals(user.name) && age.equals(user.age) && email.equals(user.email);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age, email);
    }
    
}

初始化数据

    public static void main(String[] args) {
        List<User> list =new ArrayList<>();
        list.add(new User("张三",18,null));
        list.add(new User("李四",18,null));
        list.add(new User("王二",18,null));
        list.add(new User("麻子",18,null));
    }

通过map,我们就可以让给他们加上email的值

  public static void main(String[] args) {
        List<User> list =new ArrayList<>();
        list.add(new User("张三",18,null));
        list.add(new User("李四",18,null));
        list.add(new User("王二",18,null));
        list.add(new User("麻子",18,null));
        list.stream().map(user->{
            //如果年龄等于18,则给Email赋值
            if(user.getAge()==18){
                user.setEmail("162@.com");
            }
            //将操作完的对象返回流中
            return user;
            //通过forEach遍历
        }).forEach(user->{
            System.out.println("user = " + user.toString());
        });
    }

可以看到,每一个对象都被赋予了email的值,因为他们的age都等于18
在这里插入图片描述
还可以清空麻子的年龄

  public static void main(String[] args) {
        List<User> list =new ArrayList<>();
        list.add(new User("张三",18,null));
        list.add(new User("李四",18,null));
        list.add(new User("王二",18,null));
        list.add(new User("麻子",18,null));
        list.stream().map(user->{
            //如果年龄等于18,则给Email赋值
            if(user.getName().equals("麻子")){
                user.setEmail(null);
                user.setAge(null);
            }
            //将操作完的对象返回流中
            return user;
            //通过forEach遍历
        }).forEach(user->{
            System.out.println("user = " + user.toString());
        });
    }

在这里插入图片描述
总之map操作,在项目中是比较常用的。

2.2.3 distinct

用于去除流中重复的元素

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 18, "123@.com"));
        list.add(new User("李四", 18, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.stream()
                .distinct()
                .forEach(user -> {
                    System.out.println("user = " + user.toString());
                });
    }

在这里插入图片描述
使用distinct时,务必重写equals和hashcode方法。

2.2.4 sorted

用于对流中的元素进行排序
例如,按照年龄进行降序排序

       List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("王二", 45, "123@.com"));
        list.stream().sorted((user1,user2)->{
                return user2.getAge()- user1.getAge();
                })
                .forEach(user -> {
                    System.out.println("user = " + user.toString());
                });
    }

在这里插入图片描述
升序为第一个参数减第二个参数,降序为第二个参数减第一个参数。

2.2.5 limit

限制流的长度
例如,按照年龄升序排序,只取前两个元素

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("王二", 45, "123@.com"));
        list.stream()
                .sorted((user1, user2) -> {
                    return user1.getAge() - user2.getAge();
                })
                .limit(2)
                .forEach(user -> {
                    System.out.println("user = " + user.toString());
                });
    }

在这里插入图片描述

2.2.6 skip

skip和limit相反,skip是跳过前n个元素,返回剩下的元素
例如,按照年龄升序排序,去掉重复值,取后两个元素

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        list.stream()
                .sorted((user1, user2) -> {
                    return user1.getAge() - user2.getAge();
                })
                .distinct()
                .skip(2)
                .forEach(user -> {
                    System.out.println("user = " + user.toString());
                });
    }

在这里插入图片描述

2.2.7 flatMap

map是操作一个对象,而flatMap可以操作对象集合,先将集合转换为流对象,在对流对象中的对个对象进行操作。
比如我在User中在增加一个属性

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
public class User {
private String name;
private Integer age;
private String  email;
private List<Trait> traitList;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
public class Trait {
    private Integer height;
    private Integerweight;
}

初始化值

    public static void main(String[] args) {
        List<Trait> listTrait = new ArrayList<>();
        Trait trait=new Trait(180,60);
        Trait trait1=new Trait(181,70);
        Trait trait2=new Trait(182,72);
        Trait trait3=new Trait(183,73);
        Trait trait4=new Trait(184,45);
        listTrait.add(trait);
        listTrait.add(trait1);
        listTrait.add(trait2);
        listTrait.add(trait3);
        listTrait.add(trait4);
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com",listTrait));
        list.add(new User("李四", 22, "123@.com",listTrait));
        list.add(new User("王二", 18, "123@.com",listTrait));
        list.add(new User("麻子", 45, "123@.com",listTrait));
    }

例子,打印所有数据的身高体重,按照身高降序排序

        list.stream()
                .flatMap(
                        //将身高体重的集合转为流对象
                        user->{return user.getTraitList().stream();}
                ).distinct()
                .sorted((trait11,trait22)->{return trait22.getHeight()-trait11.getHeight();})
                .forEach(user->{
                    System.out.println("user = " + user.toString());
                });

在这里插入图片描述

2.3 终结操作

流操作从创建流开始,中间操作用于对流进行处理,最后就需要终结操作来决定流最后的走向,我可以通过终结操作将流里面的数据打印出来,也可以在将流对象收集为集合,具体怎么做,就取决于我们进行怎样的终结操作。

2.3.1 forEach

对流中的元素进行遍历操作,之前演示的例子一直都是使用forEach,到这里对于forEach 的操作也比较熟悉了

2.3.2 count

获取流中元素的个数

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        long count = list.stream().count();
        System.out.println("count = " + count);
    }

在这里插入图片描述

2.3.3 max和min

获取流中的最大值或者最小值
例如,获取流中年龄最大的元素,并打印。

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        Optional<User> max = list.stream().max((user1, user2) -> {
            return user1.getAge() - user2.getAge();
        });
        System.out.println("max = " + max);
    }

在这里插入图片描述
或者,获取流中年龄最小的元素,并打印。

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        Optional<User> max = list.stream().max((user1, user2) -> {
            return  user2.getAge() - user1.getAge();
        });
        System.out.println("max = " + max);
    }

在这里插入图片描述
还记得sorted什么情况下是升序,什么情况下是降序吗?
第一个参数减第二个参数,是升序,也是最大值
第二个参数减第一个参数,是降序,也是最小值

2.3.4 collect

把流对象转换为集合。
获取一个存放所有姓名的List集合

        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        List<String> collect = list.stream().map((user -> {
            return user.getName();
        })).collect(Collectors.toList());
        //使用Stream流遍历集合
        collect.stream().forEach(userName->{
            System.out.println("userName = " + userName);
        });

在这里插入图片描述
获取一个存放所有年龄set集合

 public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        Set<Integer> collect = list.stream().map((user -> {
            return user.getAge();
        })).collect(Collectors.toSet());
        //使用Stream流遍历集合
        collect.stream().forEach(age->{
            System.out.println("age = " + age);
        });
    }

在这里插入图片描述
获取一个姓名为Key,年龄为Value的map集合

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        Map<String, Integer> collect = list.stream()
                .collect(Collectors.toMap(user -> user.getName(),
                                          user -> user.getAge()));
        //使用Stream遍历map
        Set<Map.Entry<String, Integer>> entries = collect.entrySet();
        entries.stream()
        .forEach(map -> System.out.println(map.getKey()+":"+map.getValue()));
    }

在这里插入图片描述

2.3.5 anyMatch

判断流中是否存在符合条件的元素,如果存在返回true
例如,判断是否存在年龄大于40 的user

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        boolean b = list.stream().anyMatch(user -> user.getAge() > 40);
        System.out.println("b = " + b);
    }

在这里插入图片描述

2.3.6 allMatch

判断流中的元素是否都符合条件,都符合条件返回true,否则为false。
判断流中的元素是否年龄都大于40

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        boolean b = list.stream().allMatch(user -> user.getAge() > 40);
        System.out.println("b = " + b);
    }

在这里插入图片描述

2.3.7 noneMatch

和allMatch相反,判断流中的元素是否都符合条件,都符合条件返回true,否则为false。
判断流中的元素是否年龄都大于40

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        boolean b = list.stream().noneMatch(user -> user.getAge() > 40);
        System.out.println("b = " + b);
    }

在这里插入图片描述

2.3.8 findAny

获取流中的任意一个元素

   public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        list.add(new User("麻子", 45, "123@.com"));
        Optional<User> any = list.stream().findAny();
        System.out.println(any.toString());
    }

在这里插入图片描述

2.3.9 findFirst

获取流中的第一个元素

    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("麻子", 45, "123@.com"));
        list.add(new User("张三", 34, "123@.com"));
        list.add(new User("李四", 22, "123@.com"));
        list.add(new User("王二", 18, "123@.com"));
        Optional<User> findFirst = list.stream().findFirst();
        System.out.println(findFirst.toString());
    }

在这里插入图片描述

三、注意事项

  • 惰性求值(如果没有终结操作,没有中间操作是不会得到执行的)
  • 流是一次性的(一旦一个流对象经过一个终结操作后。这个流就不能再被使用)
  • 不会影响原数据(我们在流中可以多数据做很多处理。但是正常情况下是不会影响原来集合中的元素的)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Yjd007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值