【JDK8新特性之Stream流-Stream流常用的API以及案例实操】

JDK8新特性之Stream流,不知道你在投递简历的时候有没有看到JD(工作岗位要求去描述)上写到熟悉JDK中Stream流的相关使用。如果没有的话,接下来就和我一起学习一下吧

在这里插入图片描述

1.原始集合处理数据的弊端->Stream流优势之处,案例演示

  1. 自定义一个集合,集合中给定一些名字
  2. 获取所有姓李的信息
  3. 获取名字长度为2的人员
  4. 输出所有用户的信息
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class StreamDemo01 {

    public static void main(String[] args) {

        //1. 自定义一个集合,集合中给定一些名字
        List<String> list = Arrays.asList("李一一","李一","李二二","李二");
        //2. 获取所有姓李的信息
        ArrayList<String> list1 = new ArrayList<>();
        for(String str:list){
            if(str.startsWith("李")) list1.add(str);
            else continue;
        }
        //3. 获取名字长度为2的人员
        List<String> list2 = new ArrayList<>();
        for (String s : list1) {
            if(s.length() == 2) list2.add(s);
            else continue;
        }
        //4. 输出所有用户的信息
        for (String s : list2) {
            System.out.println(s);
        }
    }
}

上面的代码针对与我们不同的需求总是一次次的循环收集记过.这时我们希望有更加高效的处理方式,这时我们就可以通过JDK8中提供的Stream API来解决这个问题了。

演进为Stream的解决方案:

import java.util.Arrays;
import java.util.List;

public class StreamDemo02 {

    public static void main(String[] args) {
        //1. 自定义一个集合,集合中给定一些名字
        List<String> list = Arrays.asList("李一一","李一","李二二","李二");
        //2. 获取所有姓李的信息、过滤、输出
        list.stream()
                .filter(str->str.startsWith("李"))
                .filter(str-> str.length()==2)
                .forEach(s-> {System.out.println(s);});
    }
}

2. Steam流式思想概述

易错点

注意:Stream和IO流没有任何关系!

基本思想

Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。如下图所示:
在这里插入图片描述

作用

Stream API能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归约。

3. Stream流的获取方式

在来看获取Stream流方式的时候我们先来看一下Java集合框架结构。
在这里插入图片描述

3.1 根据Collection获取

​ 首先,java.util.Collection 接口中加入了default方法 stream,也就是说Collection接口下的所有的实现都可以通过steam方法来获取Stream流。

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.stream();
    Set<String> set = new HashSet<>();
    set.stream();
    Vector vector = new Vector();
    vector.stream();
}

​ Map接口没有实现Collection接口,这时我们可以根据Map获取对应的key value的集合。

public static void main(String[] args) {
    Map<String,Object> map = new HashMap<>();
    Stream<String> stream = map.keySet().stream(); // key
    Stream<Object> stream1 = map.values().stream(); // value
    Stream<Map.Entry<String, Object>> stream2 = map.entrySet().stream(); // entry
}

3.2 通过Stream的of方法

注意:基本数据类型的数组是不行的
在实际开发中我们不可避免的是会操作到数组中的数据,由于数组对象不可能添加默认方法,所有Stream接口中提供了静态方法of

public class StreamDemo{

    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("q", "w", "e");
        stream1.forEach(System.out::println);
        String[] arr1 = {"aa","bb","cc"};
        Stream<String> stream2 = Stream.of(arr1);
        stream2.forEach(System.out::println);
        Integer[] arr2 = {1,2,3,4};
        Stream<Integer> stream3 = Stream.of(arr2);
        stream3.forEach(System.out::println);
    }
}

4.Stream常用方法介绍

Stream流模型的常用方法很多,这里介绍一些常用的API。这些方法可以被分成两种:

方法名方法作用返回值类型方法种类
count统计个数long终结
forEach逐一处理void终结
filter过滤Stream函数拼接
limit取用前几个Stream函数拼接
skip跳过前几个Stream函数拼接
map映射Stream函数拼接
concat组合Stream函数拼接

终结方法:返回值类型不再是 Stream 类型的方法,不再支持链式调用。本小节中,终结方法包括 count 和 forEach 方法。

非终结方法:返回值类型仍然是 Stream 类型的方法,支持链式调用。(除了终结方法外,其余方法均为非终结方法。)

Stream注意事项(重要)

  1. Stream只能操作一次

  2. Stream方法返回的是新的流

  3. Stream不调用终结方法,中间的操作不会执行

4.1 forEach

Stream流中forEach用来遍历流中的数据,该方法接受一个Consumer接口,会将每一个流元素交给函数处理

	public static void main(String[] args) {
        Stream.of("硕", "风", "和").forEach(System.out::println);;
    }

4.2 count

Stream流中的count方法用来统计其中的元素个数的该方法返回一个long值,代表元素的个数。

public class StreamDemo {

    public static void main(String[] args) {
        long count = Stream.of(1, 2, 3,4,5).count();
        System.out.println(count);
    }
}

4.3 filter

filter方法的作用是用来过滤数据的。返回符合条件的数据,可以通过filter方法将一个流转换成另一个子集流,该接口接收一个Predicate函数式接口参数作为筛选条件

public class StreamDemo {

    public static void main(String[] args) {
         Stream.of(1, 2, 3,4,5,6)
                 .filter((s)->s>=3)
                 .forEach(System.out::println);

    }
}

输出:

在这里插入图片描述

4.4 limit

limit方法可以对流进行截取处理,支取前n个数据,参数是一个long类型的数值,如果集合当前长度大于参数就进行截取,否则不操作:

public class StreamDemo{

    public static void main(String[] args) {
        Stream.of(1, 2, 3,4,5,6)
                 .limit(3)
                 .forEach(System.out::println);

    }
}

输出:

在这里插入图片描述

4.5 skip

如果希望跳过前面几个元素,可以使用skip方法获取一个截取之后的新流,案例如下所示:

public class StreamDemo{

    public static void main(String[] args) {
        Stream.of(1, 2, 3,4,5,6)
                 .skip(3)
                 .forEach(System.out::println);

    }
}

输出:

在这里插入图片描述

4.6 map类型转换

如果我们需要将流中的元素映射到另一个流中,可以使用map方法:
该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的数据

public class StreamDemo{

    public static void main(String[] args) {
        Stream.of(1, 2, 3,4,5,6)
                 .map(num->num.toString())
                 .forEach(System.out::println);

    }
}

4.7 sorted

如果需要将数据排序,可以使用sorted方法:
在使用的时候可以根据自然规则排序,也可以通过比较强来指定对应的排序规则

public class StreamDemo{

    public static void main(String[] args) {
         Stream.of("9", "6", "5","3","2","1","0")
                 .map(msg->Integer.parseInt(msg))
                 .sorted((o1,o2)->o1-o2)
                 .forEach(System.out::println);
    }
}

4.8 distinct

如果要去掉重复数据,可以使用distinct方法,案例如下:

public class StreamDemo {

    public static void main(String[] args) {
        Stream.of("9", "6","8", "5","3","2","2","1","0")
                 .map(Integer::parseInt)
                 .sorted((o1,o2)->o1-o2) 
                 .distinct() // 去掉重复的记录
                 .forEach(System.out::println);
    }
}

注意注意:Stream流中的distinct方法对于基本数据类型是可以直接出重的,但是对于自定义类型,我们是需要重写hashCode和equals方法来移除重复元素。

4.9 match

match是一个终结的方法
如果需要判断数据是否匹配指定的条件,可以使用match相关的方法
相关API如下

boolean anyMatch(Predicate<? super T> predicate); // 元素是否有任意一个满足条件
boolean allMatch(Predicate<? super T> predicate); // 元素是否都满足条件
boolean noneMatch(Predicate<? super T> predicate); // 元素是否都不满足条件

案例演示:

public class StreamDemo{

    public static void main(String[] args) {
        // 判断元素是否都大于3
        boolean b1 = Stream.of("9", "6", "8", "5", "3", "2", "2", "1", "0")
                .map(Integer::parseInt)
                .allMatch(s -> s > 3);
        System.out.println(b1);
        // 判断元素是否存在大于3的元素
        boolean b2 = Stream.of("9", "6", "8", "5", "3", "2", "2", "1", "0")
                .map(Integer::parseInt)
                .anyMatch(s -> s > 3);
        System.out.println(b2);
        // 判断元素是否都不大于3
        boolean b3 = Stream.of("9", "6", "8", "5", "3", "2", "2", "1", "0")
                .map(Integer::parseInt)
                .noneMatch(s -> s > 3);
        System.out.println(b3);
    }
}

4.10 find

如果我们需要找到某些数据,可以使用find方法来实现,如下面所示,案例如下:

public class StreamDemo{

    public static void main(String[] args) {

        Optional<String> first = Stream.of("1", "5", "1").findFirst();
        System.out.println(first.get());

        Optional<String> any = Stream.of("1", "1", "7").findAny();
        System.out.println(any.get());
    }
}

4.11 max和min

如果我们想要获取最大值和最小值,那么可以使用max和min方法,案例如下:

public class StreamDemo{

    public static void main(String[] args) {

        Optional<Integer> min = Stream.of("9", "6","8", "5","3","2","2","1","0")
                .map(Integer::parseInt)
                .min((o1,o2)->o2-o1);// 取来排序后第一个元素的位置为元素的最小值
        System.out.println(min.get());

        Optional<Integer> max = Stream.of("9", "6","8", "5","3","2","2","1","0")
                .map(Integer::parseInt)
                .max((o1,o2)->o2-o1);// 取来排序后最后一个元素的位置为元素的最大值
        System.out.println(max.get());
    }
}

4.12 reduce方法

如果需要将所有数据归纳得到一个数据,可以使用reduce方法,案例如下:

public class StreamDemo {

    public static void main(String[] args) {
        Integer sum = Stream.of("9", "6","8", "5","3","2","2","1","0")
                .map(Integer::parseInt)
                // 第一次的时候会将默认值赋值给x,以后每次将上一次的操作结果赋值给x y就是每次从数据中获取的元素
                .reduce(0, (x, y) -> {
                    //System.out.println("x:"+x+",y:"+y);
                    return x + y;
                });
        System.out.println(sum);
    }
}

4.13 map和reduce的组合

在实际开发中我们经常会将map和reduce一块来使用

public class StreamDemo {

    public static void main(String[] args) {
        // 1.求出所有年龄的总和
        Integer sumAge = Stream.of(
                new Person("a", 18)
                , new Person("b", 22)
        ).map(Person::getAge) // 实现数据类型的转换
                .reduce(0, Integer::sum);
        System.out.println(sumAge);

        // 2.求出所有年龄中的最大值
        Integer maxAge = Stream.of(
                new Person("a", 18)
                , new Person("b", 22)
        ).map(Person::getAge) // 实现数据类型的转换,符合reduce对数据的要求
                .reduce(0, Math::max); // reduce实现数据的处理
        System.out.println(maxAge);
        // 3.统计 字符 a 出现的次数
        Integer count = Stream.of("a", "b", "c", "d", "a", "c", "a")
                .map(ch -> "a".equals(ch) ? 1 : 0)
                .reduce(0, Integer::sum);
        System.out.println(count);
    }
}

4.14 mapToInt

如果需要将Stream中的Integer类型转换成int类型,可以使用mapToInt方法来实现,案例如下

public class StreamDemo{

    public static void main(String[] args) {
        // Integer占用的内存比int多很多,在Stream流操作中会自动装修和拆箱操作
        Integer arr[] = {7,4,3,6,7,3,4};
        // 为了提高程序代码的效率,我们可以先将流中Integer数据转换为int数据,然后再操作
        IntStream intStream = Stream.of(arr)
                .mapToInt(Integer::intValue);
        intStream.filter(i->i>3)
                .forEach(System.out::println);

    }
}

4.15 concat

如果有两个流,希望合并成为一个流,那么可以使用Stream接口的静态方法concat,案例如下:

public class StreamDemo{

    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("1","2","3");
        Stream<String> stream2 = Stream.of("3", "2", "1");
        Stream.concat(stream1,stream2).forEach(System.out::println);
    }
}

5. 总结

现在面试考察的范围越来越广,这就需要在平常的学习生活中不断的积累,等待厚积薄发的时候。
既然都看到这里了,那就留下你的关注吧,我是硕风和炜,我们下篇文章见哦!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

硕风和炜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值