当我们对一个集合中的元素进行多次过滤应该怎样做?
下面看一个案例
按照下面的要求完成集合的创建和遍历
创建一个集合,存储多个字符串元素
把集合中所有以"张"开头的元素存储到一个新的集合
把"张"开头的集合中的长度为3的元素存储到一个新的集合
遍历上一步得到的集合
原始方式示例代码
- public class MyStream1 {
- public static void main(String[] args) {
- //集合的批量添加
- ArrayList
list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤")); - //list.add()
-
- //遍历list1把以张开头的元素添加到list2中。
- ArrayList
list2 = new ArrayList<>(); - for (String s : list1) {
- if(s.startsWith("张")){
- list2.add(s);
- }
- }
- //遍历list2集合,把其中长度为3的元素,再添加到list3中。
- ArrayList
list3 = new ArrayList<>(); - for (String s : list2) {
- if(s.length() == 3){
- list3.add(s);
- }
- }
- for (String s : list3) {
- System.out.println(s);
- }
- }
- }
使用Stream流示例代码
- public class test1 {
- public static void main(String[] args) {
- //集合的批量添加
- ArrayList
list1 = new ArrayList<>(List.of("张三丰", "张无忌", "张翠山", "王二麻子", "张良", "谢广坤")); -
- //Stream流
- list1.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
-
- }
- }
由此可见
Java Stream流的好处体现在以下几个方面:
总的来说,Java Stream流通过提供一种高效、简洁、易于维护的方式来处理数据,极大地提升了开发效率和程序的性能。
获取Stream流
创建一条流水线,并把数据放到流水线上准备进行操作
中间方法
流水线上的操作
一次操作完毕之后,还可以继续进行其他操作
终结方法
一个Stream流只能有一个终结方法
是流水线上的最后一个操作
生成Stream流的方式
Collection体系集合
使用默认方法stream()生成流, default Stream
- public class test5 {
- public static void main(String[] args) {
-
- int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
-
- //获取stream流
- Arrays.stream(arr).forEach(s -> System.out.println(s));
- }
- }
Map体系集合
把Map转成Set集合,间接的生成流
- public class test3 {
- public static void main(String[] args) {
- //双列集合
-
- //1.创建双列集合
- HashMap
hm = new HashMap<>(); -
- //添加数据
- hm.put("aaa",111);
- hm.put("bbb",111);
- hm.put("ccc",111);
- hm.put("ddd",111);
-
- //3.第一种获取Stream流
- hm.keySet().stream().forEach(s -> System.out.println(s));
-
- //3.第二种获取Stream流
- hm.entrySet().stream().forEach(s -> System.out.println(s));
-
-
- }
- }
数组
通过Arrays中的静态方法stream生成流
- public class test2 {
- public static void main(String[] args) {
- //单列集合获取Stream流
- ArrayList
list = new ArrayList<>(); - Collections.addAll(list,"a","b","c","d");
-
- list.stream().forEach(s -> System.out.println(s));
- }
- }
同种数据类型的多个数据
通过Stream接口的静态方法of(T... values)生成流
- public class test4 {
- public static void main(String[] args) {
- Stream.of(1,2,3,4,5).forEach(s -> System.out.println(s));
- }
- }
概念
中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作
常见方法
| 方法名 | 说明 |
|---|---|
| Stream | 用于对流中的数据进行过滤 |
| Stream | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
| Stream | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
| static | 合并a和b两个流为一个流 |
| Stream | 返回由该流的不同元素(根据Object.equals(Object) )组成的流 |
- public class MyStream3 {
- public static void main(String[] args) {
- // Stream
filter(Predicate predicate):过滤 - // Predicate接口中的方法 boolean test(T t):对给定的参数进行判断,返回一个布尔值
-
- ArrayList
list = new ArrayList<>(); - list.add("张三丰");
- list.add("张无忌");
- list.add("张翠山");
- list.add("王二麻子");
- list.add("张良");
- list.add("谢广坤");
-
- //filter方法获取流中的 每一个数据.
- //而test方法中的s,就依次表示流中的每一个数据.
- //我们只要在test方法中对s进行判断就可以了.
- //如果判断的结果为true,则当前的数据留下
- //如果判断的结果为false,则当前数据就不要.
- // list.stream().filter(
- // new Predicate
() { - // @Override
- // public boolean test(String s) {
- // boolean result = s.startsWith("张");
- // return result;
- // }
- // }
- // ).forEach(s-> System.out.println(s));
-
- //因为Predicate接口中只有一个抽象方法test
- //所以我们可以使用lambda表达式来简化
- // list.stream().filter(
- // (String s)->{
- // boolean result = s.startsWith("张");
- // return result;
- // }
- // ).forEach(s-> System.out.println(s));
-
- list.stream().filter(s ->s.startsWith("张")).forEach(s-> System.out.println(s));
-
- }
- }
limit&skip代码演示
- public class StreamDemo02 {
- public static void main(String[] args) {
- //创建一个集合,存储多个字符串元素
- ArrayList
list = new ArrayList(); -
- list.add("林青霞");
- list.add("张曼玉");
- list.add("王祖贤");
- list.add("柳岩");
- list.add("张敏");
- list.add("张无忌");
-
- //需求1:取前3个数据在控制台输出
- list.stream().limit(3).forEach(s-> System.out.println(s));
- System.out.println("--------");
-
- //需求2:跳过3个元素,把剩下的元素在控制台输出
- list.stream().skip(3).forEach(s-> System.out.println(s));
- System.out.println("--------");
-
- //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
- list.stream().skip(2).limit(2).forEach(s-> System.out.println(s));
- }
- }
concat&distinct代码演示
- public class StreamDemo03 {
- public static void main(String[] args) {
- //创建一个集合,存储多个字符串元素
- ArrayList
list = new ArrayList(); -
- list.add("林青霞");
- list.add("张曼玉");
- list.add("王祖贤");
- list.add("柳岩");
- list.add("张敏");
- list.add("张无忌");
-
- //需求1:取前4个数据组成一个流
- Stream
s1 = list.stream().limit(4); -
- //需求2:跳过2个数据组成一个流
- Stream
s2 = list.stream().skip(2); -
- //需求3:合并需求1和需求2得到的流,并把结果在控制台输出
- // Stream.concat(s1,s2).forEach(s-> System.out.println(s));
-
- //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
- Stream.concat(s1,s2).distinct().forEach(s-> System.out.println(s));
- }
- }
- public class test6 {
- public static void main(String[] args) {
- /*
- map 转换流中的数据类型
- 注意点1: 中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
- 注意点2: 修改Stream流中的数据,不会影响原来集合或者数组中的数据
- */
-
- ArrayList
list = new ArrayList<>(); - Collections.addAll(list,"张三-15","李四-16");
-
- //需求: 只获取里面的年龄并进行打印
- //String -> int
- //第一个类型: 流中原来的数据类型
- //第二个类型: 要转成之后的数据
-
- list.stream().map(new Function
() { - @Override
- public Integer apply(String s) {
- String[] arr = s.split("-");
- String ageString = arr[1];
- int age = Integer.parseInt(ageString);
- return age;
- }
- }).forEach(s -> System.out.println(s));
-
- list.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(s -> System.out.println(s));
-
- }
- }
概念
终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作
常见方法
| 方法名 | 说明 |
|---|---|
| void forEach(Consumer action) | 对此流的每个元素执行操作 |
| long count() | 返回此流中的元素数 |
概念
对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中
常用方法
| 方法名 | 说明 |
|---|---|
| R collect(Collector collector) | 把结果收集到集合中 |
工具类Collectors提供了具体的收集方式
| 方法名 | 说明 |
|---|---|
| public static | 把元素收集到List集合中 |
| public static | 把元素收集到Set集合中 |
| public static Collector toMap(Function keyMapper,Function valueMapper) | 把元素收集到Map集合中 |
- public class StreamTest5 {
- // toList和toSet方法演示
- public static void main(String[] args) {
-
- ArrayList
list1 = new ArrayList<>(); - for (int i = 1; i <= 10; i++) {
- list1.add(i);
- }
-
- list1.add(10);
- list1.add(10);
- list1.add(10);
- list1.add(10);
- list1.add(10);
-
- //filter负责过滤数据的.
- //collect负责收集数据.
- //获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中.
- //Collectors.toList() : 在底层会创建一个List集合.并把所有的数据添加到List集合中.
- List
list = list1.stream().filter(number -> number % 2 == 0).collect(Collectors.toList()); - System.out.println(list);
-
- Set
set = list1.stream().filter(number -> number % 2 == 0) - .collect(Collectors.toSet());
- System.out.println(set);
- }
- }
- public class StreamTest6 {
- public static void main(String[] args) {
- /*
- Stream流的收集方法 toMap方法演示
- 创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄
- "zhangsan,23"
- "lisi,24"
- "wangwu,25"
- 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
- */
- ArrayList
list = new ArrayList<>(); - list.add("zhangsan,23");
- list.add("lisi,24");
- list.add("wangwu,25");
-
- Map
map = list.stream().filter( - s -> {
- String[] split = s.split(",");
- int age = Integer.parseInt(split[1]);
- return age >= 24;
- }
-
- // collect方法只能获取到流中剩余的每一个数据.
- //在底层不能创建容器,也不能把数据添加到容器当中
-
- ).collect(Collectors.toMap(
- s -> s.split(",")[0],
- s -> Integer.parseInt(s.split(",")[1])));
-
- System.out.println(map);
- }
-
- }
案例来源:
//https://www.bilibili.com/video/BV17F411T7Ao/?spm_id_from=333.337.search-card.all.click