JDK8新特性详解Lambda&Stream

2022-05-25 11:01:48 浏览数 (1)

目录

  • 1 Lambda
    • 1.1 为什么使用lambda
    • 1.2 lambda案例
    • 1.3 lambda语法规则
      • 1.3.1 接口里面只能有一个方法
    • 1.4 lambda使用前提
  • 2 Stream
    • 2.1为什么使用这个
    • 2.2 入门代码
    • 2.3 思想
    • 2.4 stream流的获取方式
    • 2.5 stream里面的方法
      • 2.5.1 forEach
      • 2.5.2 count
      • 2.5.3 filter
      • 2.5.4 limit
      • 2.5.5 skip
      • 2.5.6 map
      • 2.5.7 sorted
      • 2.5.8 distinct
      • 2.5.9 reduce
      • 2.5.10 concat
      • 2.5.11 parallelStream
      • 2.5.12 findFirst()
      • 2.5.13 anyMatch
    • 2.6 综合案例
    • 2.7 stream 结果集
      • 2.7.1 结果收集到集合中
      • 2.7.2 结果收集到数组中
    • 2.8 对流中的数据做聚合计算
    • 2.9 对流中的数据做分组
    • 2.10 对流中的数据做分区操作
    • 2.11 对流中的数据做拼接功能
    • 2.12 并行流
    • 2.13 并行流与串行流对比
    • 2.14 使用并行流的线程安全问题
  • 3 stream技巧
    • 3.1 数组转集合
    • 3.2 统计数组元素中的个数

1 Lambda

1.1 为什么使用lambda

1.2 lambda案例

代码语言:javascript复制
new Thread(()-> {
            System.out.println("lambda");
            System.out.println("666");
        }).start();

1.3 lambda语法规则

1.3.1 接口里面只能有一个方法

代码语言:javascript复制
@FunctionalInterface
public interface UserService {

    void getname();
}

我们要使用lambda表达式,接口里面只能有一个方法,但是有可能其他人往这个接口里面写代码,所以我们在这个接口里面写一个注解@FunctionalInterface;这个接口就是一个标注注解,被这个注解修饰的接口,只能有一个抽象方法

1.4 lambda使用前提

2 Stream

2.1为什么使用这个

我们自己定义一个list集合,要使用里面的数据,我们就需要一直的循环,多一个需求,就多一次循环,这样是不好的,很复杂;

其实就是简化了我们对集合的操作,对数组的操作

2.2 入门代码

代码语言:javascript复制
List<String> strings = Arrays.asList("张三", "张四", "王五", "赵六");
strings.stream()
       .filter(s -> s.startsWith("张"))
       .filter(s -> s.length()==2)
       .forEach(s -> System.out.println(s));

2.3 思想

stream就是一个流水线

2.4 stream流的获取方式

直接对数组进行操作

2.5 stream里面的方法

2.5.1 forEach

2.5.2 count

代码语言:javascript复制
        Stream<String> a1 = Stream.of("a1", "a2", "a3");
        long count = a1.count();
        System.out.println(count);

2.5.3 filter

代码语言:javascript复制
List<String> strings = Arrays.asList("张三", "张四", "王五", "赵六");
strings.stream()
        .filter(s -> s.startsWith("张"))
        .filter(s -> s.length()==2)
        .forEach(s -> System.out.println(s));

2.5.4 limit

相当于分页,截取多少个数据

代码语言:javascript复制
 List<String> strings = Arrays.asList("张三", "张四", "王五", "赵六");
        strings.stream()
                .filter(s -> s.startsWith("张"))
                .filter(s -> s.length()==2)
                .limit(1)   取出1个元素
                .forEach(s -> System.out.println(s));

2.5.5 skip

代码语言:javascript复制
List<String> strings = Arrays.asList("张三", "张四", "王五", "赵六");
strings.stream()
        .skip(1)
        .forEach(s -> System.out.println(s));

2.5.6 map

2.5.7 sorted

代码语言:javascript复制
 List<Integer> strings1 = Arrays.asList(1, 2, 3, 4);
 strings1.stream()
         .sorted() //默认是从小到大排序
         .sorted((o1,o2)-> o2-o1) //自定义排序规则
         .forEach(s -> System.out.println(s));

2.5.8 distinct

排除相同的数据

代码语言:javascript复制
 List<Integer> strings1 = Arrays.asList(1, 1, 3, 4);
 strings1.stream()
         .sorted() //默认是从小到大排序
         .sorted((o1,o2)-> o2-o1) //自定义排序规则
         .distinct()//去掉重复的数据
         .forEach(s -> System.out.println(s));

2.5.9 reduce

2.5.10 concat

2.5.11 parallelStream

获取一个并行流

代码语言:javascript复制
ArrayList<Object> objects = new ArrayList<>();
Stream<Object> objectStream = objects.parallelStream();

2.5.12 findFirst()

匹配出流里面的第一个数据

代码语言:javascript复制
// 匹配第一个
Optional<Integer> findFirst = list.stream().
filter(x -> x > 6).findFirst();

2.5.13 anyMatch

// 是否包含符合特定条件的元素

代码语言:javascript复制
// 是否包含符合特定条件的元素
boolean anyMatch = list.stream().anyMatch(x -> x > 6);

2.6 综合案例

代码语言:javascript复制
    public static void main(String[] args) {
//        创建两个list
        List<String> list1 = Arrays.asList("迪丽热巴", "古力娜扎", "孙悟空", "租八戒", "唐生");
        List<String> list2 = Arrays.asList("张无忌", "赵敏", "刘亦菲", "张三分", "张姐","胡歌", "纳兰性德");
// 从list1里面得到长度为3的,并且只要前三个
        Stream<String> stream1 = list1.stream()
                .filter(s -> s.length() == 3)
                .limit(3);
//从list2中筛选只要张姓的人,并且不要最前面的两个人
        Stream<String> stream2 = list2.stream()
                .filter(s -> s.startsWith("张"))
                .skip(1);
// 将两个合并为一个
        Stream<String> concat = Stream.concat(stream1, stream2);
//        根据姓名创建对象
        Stream<person> personStream = concat.map(s -> new person(s));
//        将对象输出
        personStream.forEach(s ->{
            System.out.println(s.getName());
        });

2.7 stream 结果集

我们通过stream过滤完数据,需要将结果保存

2.7.1 结果收集到集合中

代码语言:javascript复制
//        将过滤之后的数据转为list集合
        List<person> collect = personStream.collect(Collectors.toList());
        System.out.println(collect.toString());
//        将过滤之后的数据转为set集合
      Set<person> collect1 = personStream.collect(Collectors.toSet());
        System.out.println(collect1.toString());
代码语言:javascript复制
转换成特定的实现类
        ArrayList<person> collect = personStream.collect(Collectors.toCollection(() -> new ArrayList<>()));
        System.out.println(collect.toString());

2.7.2 结果收集到数组中

代码语言:javascript复制
        String[] strings = Stream.of("1", "2", "3").toArray(String[]::new);

        System.out.println(Arrays.toString(strings)); //[1, 2, 3]

2.8 对流中的数据做聚合计算

代码语言:javascript复制
    public static void main(String[] args) {

        //从数据库查询出来的值
        Stream<person> personStream = Stream.of(
                new person("小红", 15),
                new person("小百", 14),
                new person("小天", 18),
                new person("小让", 85),
                new person("小与", 4)
        );

        //获取list里面的年龄的最大值
//        Optional<person> collect = personStream.
//                collect(Collectors.maxBy((p1, p2) -> p1.getAge() - p2.getAge()));
//        System.out.println(collect.get());


    //获取list里面的年龄的最小值
//                Optional<person> collect = personStream.
//                collect(Collectors.minBy((p1, p2) -> p1.getAge() - p2.getAge()));
//        System.out.println(collect.get());


//        求和
//        Integer collect = personStream.
//                collect(Collectors.summingInt(person::getAge));

//        平均值
//        Double collect = personStream.collect(Collectors.averagingInt(person::getAge));

//        统计数量
        Long collect = personStream.collect(Collectors.counting());

    }

2.9 对流中的数据做分组

代码语言:javascript复制
 public static void main(String[] args) {
        //从数据库查询出来的值
        Stream<person> personStream = Stream.of(
                new person("小红", 15),
                new person("小百", 15),
                new person("小天", 18),
                new person("小让", 18),
                new person("小与", 19)
        );

//        以某一个字段进行分组
//        Map<String, List<person>> collect = personStream.collect(Collectors.groupingBy(person::getName));
//        collect.forEach((k,v)-> System.out.println("k=" k "====" "v=" v));
//        k=小让====v=[person{name='小让', age=18}]
//        k=小天====v=[person{name='小天', age=18}]
//        k=小与====v=[person{name='小与', age=4}]
//        k=小百====v=[person{name='小百', age=15}]
//        k=小红====v=[person{name='小红', age=15}]


//        以成年未成年进行分组
//        Map<String, List<person>> collect = personStream.collect(Collectors.groupingBy(p -> {
//            return p.getAge() > 18 ? "成年" : "未成年";
//        }));
//        System.out.println(collect);

//       多级分组
        Map<String, Map<Object,List<person>>> collect =personStream.collect(
                Collectors.groupingBy(
                        person::getName,
                        Collectors.groupingBy(p -> {
                        return p.getAge() > 18 ? "成年" : "未成年";
                        })
         ));
        System.out.println(collect);
    }

2.10 对流中的数据做分区操作

代码语言:javascript复制
//从数据库查询出来的值
        Stream<person> personStream = Stream.of(
                new person("小红", 15),
                new person("小百", 15),
                new person("小天", 18),
                new person("小让", 18),
                new person("小与", 19)
        );

        Map<Boolean, List<person>> collect = personStream.collect(Collectors.partitioningBy(person -> person.getAge() > 10));
        System.out.println(collect);

结果

代码语言:javascript复制
{false=[], 
true=[person{name='小红', age=15}, 
		person{name='小百', age=15}, 
		person{name='小天', age=18}, 
		person{name='小让', age=18}, 
		person{name='小与', age=19}]}

2.11 对流中的数据做拼接功能

代码语言:javascript复制
    public static void main(String[] args) {
        //从数据库查询出来的值
        Stream<person> personStream = Stream.of(
                new person("小红", 15),
                new person("小百", 15),
                new person("小天", 18),
                new person("小让", 18),
                new person("小与", 19)
        );

//        Map<Boolean, List<person>> collect = personStream.collect(Collectors.partitioningBy(person -> person.getAge() > 10));
//        System.out.println(collect);

//        拼接

        String collect = personStream
                .map(person -> person.getName())
                .collect(Collectors.joining("_", "&&&", "wwww"));
        System.out.println(collect);
代码语言:javascript复制
&&&小红_小百_小天_小让_小与wwww

2.12 并行流

获取并行流的2个方式

代码语言:javascript复制
        List<String> list1 = Arrays.asList("迪丽热巴", "古力娜扎", "孙悟空", "租八戒", "唐生");
        //获取并行流  第一个方式
        Stream<String> stringStream = list1.parallelStream();
//        第二个
        Stream<String> parallel = Stream.of("1", "2").parallel();

2.13 并行流与串行流对比

2.14 使用并行流的线程安全问题

就是我们从数据库查询出list数据,过滤完成之后往新的list集合里面添加数据,那么如果使用并行流遍历,会出现线程安全问题

代码语言:javascript复制
public static void main(String[] args) {
        ArrayList<Object> objects = new ArrayList<>();
        for(int i=0;i<2000;i  ){
            objects.add(i);
        }
        System.out.println(objects.size());

        ArrayList<Object> rrrr = new ArrayList<>();
        objects.parallelStream().forEach(f->{
            rrrr.add(f);
        });

        System.out.println(rrrr.size());

    }

以上代码会出现的错误

我们的解决方法是 1 加一个同步代码块

代码语言:javascript复制
   public static void main(String[] args) {
        ArrayList<Object> objects = new ArrayList<>();
        for(int i=0;i<2000;i  ){
            objects.add(i);
        }
        System.out.println(objects.size());
        Object obj = new Object();
        ArrayList<Object> rrrr = new ArrayList<>();
        objects.parallelStream().forEach(f->{
            synchronized (obj){
                rrrr.add(f);
            }

        });

        System.out.println(rrrr.size());

    }

3 stream技巧

3.1 数组转集合

之前我们写代码

代码语言:javascript复制
// 将 List 元素存储到数组中
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
int[] arr = new int[list.size()];
Integer[] temp = list.toArray(new Integer[0]);
for (int i = 0; i < temp.length; i  ) {
 arr[i] = temp[i];
}

// 将数组元素 存储到 List 中
int[] arr = {1, 2, 3, 4, 5};
List<Integer> list = new ArrayList<>();
for (int val : arr) {
 list.add(val);
}

现在写

代码语言:javascript复制
// 将 List 元素存储到数组中
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
int[] arr = list.stream().mapToInt(Integer::intValue).toArray();

// 将数组元素 存储到 List 中
int[] arr = {1, 2, 3, 4, 5};
List<Integer> list = IntStream.of(arr).boxed().collect(Collectors.toList());

3.2 统计数组元素中的个数

假设我们现在需要统计并输出一个有重复元素的数组中每个元素及对应元素出现的个数,相信各位都能够想到,我们使用一个Map就很容易解决这个问题,代码如下:

代码语言:javascript复制
String[] arr = {"a", "c", "a", "b", "d", "c"};
Map<String, Integer> map = new HashMap<>();
for (String s : arr) {
    if (map.containsKey(s)) {
        map.put(s, map.get(s)   1);
    } else {
        map.put(s, 1);
    }
}
map.forEach((key, value) -> System.out.println(key   " : "   value));
代码语言:javascript复制
String[] arr = {"a", "c", "a", "b", "d", "c"};
Stream.of(arr)
      .collect(Collectors.toMap(k -> k, k -> 1, Integer::sum))
      .forEach((k, v) -> System.out.println(k   " : "   v));

在上面的代码中,Collectors.toMap(k -> k, k -> 1, Integer::sum)这一部分可能不好理解,对于这里面的三个参数,第一个参数代表将arr中的每一个元素作为Map中的key,第二个参数代表每一个key所对应的value,在这里每一个元素都对应个数1,第三个参数代表,如果存在相同的key,该如何进行合并,这里通过使用Integer::sum,代表将具有相同key的元素进行合并时,其value进行相加,这样便实现了每个元素个数的统计

0 人点赞