Stream流的使用步骤,获取,中间方法,终结方法

目录

Stream流的作用

Stream流的使用步骤

获取Steam流

1.单列集合获取Stream流

2.双列集合获取Stream流

3.数组获取Stream流

4.一堆零散数据获取Stream流

Stream流的中间方法

注意点:

方法解析

Stream流的终结方法


Stream流的作用

结合了Lambda表达式,简化集合、数组的操作

Stream流的使用步骤

  1. 先得到一条Stream流(流水线),并把数据放上去;

利用Stream流中的API进行各种操作。流的API有中间方法终结方法,中间方法调用完毕后,还能调用其他的方法;中介方法是最后一步调用的,调用完毕后不能再调用其他方法。

  1. 使用中间方法对流水线上的数据进行操作;

  2. 使用终结方法对流水线上的数据进行操作;

获取Steam流

获取方式方法名说明
单列集合(Collection)default Stream<E> stream()Collection中的默认方法
双列集合(Map)无法直接使用Stream流(先转成单列集合)
数组public static<T> Stream<T> stream(T[] array)Arrays工具类中的静态方法
零散数据public static<T> Stream<T> of(T... values)Stream接口中的静态方法

1.单列集合获取Stream流

//导包
import java.util.stream.Stream;
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7);
//获取一条流,并把集合的数据放到流上
//1.用Stream变量接受再打印
Stream<Integer> stream1 = list.stream();
stream1.forEach(i -> System.out.print(i + " "));
//2.通常链式编程直接使用从单列集合获取的Stream流
list.stream().forEach(i -> System.out.print(i + " "));

2.双列集合获取Stream流

第一种方法:使用keySet方法

//1)创建双列集合
HashMap<String, Integer> hm = new HashMap<>();
//2).添加数据
hm.put("aaa", 1);
hm.put("bbb", 2);
hm.put("ccc", 3);
hm.put("ddd", 4);
hm.put("eee", 5);
//3)第一种获取双列集合Stream流的办法
hm.keySet().stream().forEach(k -> System.out.println(k + "=" + hm.get(k)));

第二种方法:使用entrySet方法

hm.entrySet().stream().forEach(entry -> System.out.println(entry.getKey() + "=" + entry.getValue()));

前面创建双列集合的步骤不变

3.数组获取Stream流

//1)创建数组
int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7};
//2)通过类名Arrays调用stream方法,来获取数组的Stream流
Arrays.stream(arr).forEach(i -> System.out.print(i + " "));

不同的是,获取数组的Stream流方法是类 Arrays的静态方法,可以直接通过 类名. 的形式调用。

基本数据类型和引用数据类型的数组 用法一样。

4.一堆零散数据获取Stream流

//调用Stream接口中的静态方法of
Stream.of(1, 2, 3, 4, 5).forEach(i -> System.out.print(i + " "));

基本数据类型和引用数据类型的用法一样。

注:必须是数据类型相同的一堆数据。

注意一个易错点:Stream的of方法接受零散数据的原理是可变参数,所以这个方法也可以获取数组的流。

不过注意 :Stream的of方法的可变形参是泛型T,只能接收引用数据类型,如果传递了基本数据类型的数组作为参数,那么会把整个数组的地址作为一个元素放到Stream中。

String[] strs = {"a", "b", "c"};
Stream.of(strs).forEach(s -> System.out.println(s));//可以正常打印元素a,b,c
//String 是引用数据类型
int[] arr1 = {1, 2, 3};
Stream.of(arr1).forEach(i -> System.out.println(i + " "));//[I@27973e9b 
//int 是基本数据类型

Stream流的中间方法

常用API

名称说明
Stream<T> filter(Predicate<? super T> predicate)过滤
Stream<T> limit(long maxSize)获取前几个元素
Stream<T> skip(long n)跳过前几个元素,获取后面的
Stream<T> distinct()元素去重,依赖(hashCode和equals方法)
static <T> Stream<T> concat(Stream a, Stream b)合并a和b两个流为一个流
Stream<R> map(Function<T, R> mapper)转换流中的数据类型

注意点:

  1. 中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程。

  2. 修改Stream流中的数据,不会影响原来集合或者数组中的数据

//创建集合 后面的代码演示都用这个集合
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "a","abs","aa","bs","dfs");

注意点演示

1)

//导包
import java.util.stream.Stream;

Stream<String> stream = list.stream();
Stream<String> stream1 = stream.filter(s -> s.startsWith("a"));
//打印流stream
stream.forEach(s -> System.out.println(s));
//打印流stream1
stream1.forEach(s -> System.out.println(s));

这段代码我先将上面的集合获取到流stream中,然后调用stream的filter过滤方法得到新的流stream1;

再分别打印流stream和stream1。

编译不会报错,运行时得到如下结果:

 

报错:流已经被操作或关闭;

说明一个流只能使用一次。为了简化代码的书写,也为了避免流的误操作,通常采用链式编程进行书写。

2)

流的使用不会影响原集合或数组中的数据

方法解析

1)filter

//导包
import java.util.function.Predicate;
.
.
.
​
list.stream().filter(new Predicate<String>() {
    @Override
    public boolean test(String s) {
        //如果返回值为true,表示当前数据留下
        //如果返回值为false,表示当前数据舍弃
        return s.startsWith("a");
    }
}).forEach(s -> System.out.println(s));

Lambda表达式简化

list.stream().filter(s -> s.startsWith("a")).forEach(s -> System.out.println(s));

2)limit

获取前几个(参数)元素。

list.stream().limit(3).forEach(System.out::println);

3)skip

跳过前几个(参数)元素,获取后面的所有元素。

list.stream().skip(3).forEach(System.out::println);

4)distinct

元素去重,依赖(hashCode和equals方法)。

list.stream().distinct().forEach(System.out::println);
//底层使用 HashSet 去重。

因为distinct底层使用HashSet去重,所以如果是java打包好的类型还好,如果是自定义类型一定要重写hashCode和equals方法

5)concat

连接两个流

ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"1","2","3","4");
​
//5.Stream.concat()
Stream.concat(list1.stream(), list.stream()).forEach(System.out::println);

concat是Stream类里的静态方法(static),使用 类名. 调用。

concat可以连接类型相同的流,获取到的新的流的类型不变;

List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
Stream<String> stream = Stream.concat(list1.stream(), list2.stream());

concat也可以连接类型不同的流,获取到的新的流的类型变成两个类型的父类

List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
Stream<Object> stream = Stream.concat(list1.stream(), list2.stream());

6)map

//6.map
list.clear();
Collections.addAll(list, "a-2","c-4","d-0","b-9");
//使用map方法将流中的整数提取出来
/*
        * map中       Function的第一个泛型表示流里面数据的类型,第二个泛型表示要转成的类型
        *             apply方法
        *                       形参:依次表示流中的每个数据
        *                       返回值:转换类型后的数据
        *                       方法体:要写将一个数据转换数据类型
        * */
list.stream().map(new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
        String[] arr = s.split("-");
        return Integer.parseInt(arr[1]);
    }
}).forEach(System.out::println);

Lambda表达式简化后

list.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(System.out::println);

map方法中函数式接口Function泛型的两个参数

第一个参数是流中原本的数据类型;

第二个类型是转换之后的类型;

接口的方法

apply的形参s:依次表示流里面的每一个元素;

返回值表示转换之后的数据。

当map方法执行完毕之后,留下的数据都是转换之后的结果。

Stream流的终结方法

名称说明
void forEach(Consumer action)遍历
long count()统计
toArray()收集流中的数据,放到数组中
collect(Collector collector)收集流中的数据,放到集合中

ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1,2,3,4,5);

1)forEach

//1.void forEach(Consumer action) 遍历

//Consumer的泛型,表示流中数据的类型
//accept方法的形参s:以此表示流中的每一个数据
//方法体:对每一个数据的处理操作(打印)
list.stream().forEach(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) {
        System.out.println(integer);
    }
});

Lambda表达式简化

list.stream().forEach(i -> System.out.println(i));

2)long count()

统计流中元素个数。

//2.long count() 统计流中元素个数
System.out.println(list.stream().count());

3)toArray

收集元素,转成数组。

空参:直接转成Object类型的数组

//3.toArray() 收集元素,转成数组
Object[] arr1 = list.stream().toArray();
System.out.println(Arrays.toString(arr1));

含参:

//含参
​
//IntFunction的泛型:具体类型的数组
//apply的形参:流中数据的个数,要跟数组的长度保持一致
//apply的返回值:具体类型的数组
//方法体:创建数组
​
//toArray方法的参数是创建一个指定长度的数组
//toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
//toArray方法的返回值:是一个装着流里面所有数据的数组
Integer[] arr2 = list.stream().toArray(new IntFunction<Integer[]>() {
    @Override
    public Integer[] apply(int value) {
        return new Integer[value];
    }
});
System.out.println(Arrays.toString(arr2));

Lambda表达式简化

Integer[] arr3 = list.stream().toArray(value -> new Integer[value]);

或者

Integer[] arr3 = list.stream().toArray(Integer[]::new);

4)collect(Collector collector) 收集流中的数据,放到集合中

4.1)收集到List集合当中

//4.1) 收集到集合当中
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1, "9-aabc","0-uud","4-iwj","7-dads","10-doqw","99-lsks");
List<String> newList = list1.stream()
    .filter(s -> Integer.parseInt(s.split("-")[0]) < 10)
    .collect(Collectors.toList());
System.out.println("newList" + newList);

收集到List集合中也可以用Stream中的非静态方法toList()

//4.1) 收集到集合当中
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1, "9-aabc","0-uud","4-iwj","7-dads","10-doqw","99-lsks");
List<String> newList = list1.stream()
    .filter(s -> Integer.parseInt(s.split("-")[0]) < 10)
    .toList();
System.out.println("newList" + newList);

4.2)收集到Set集合当中

//4.2) 收集到Set集合当中
Set<String> newList2 = list1.stream()
    .filter(s -> Integer.parseInt(s.split("-")[0]) < 10)
    .collect(Collectors.toSet());
System.out.println("newList2" + newList2);

收集到Set集合中可以自动去重

4.3)收集到Map集合当中

//导包
import java.util.stream.Collectors;
//4.3) 收集到map集合当中
Map<Integer, String> map = list1.stream()
    .filter(s -> Integer.parseInt(s.split("-")[0]) < 10)
    /*
                 *Collectors.toMap()方法的 第一个参数:表示键的生成规则;
                 *                        第二个参数:表示值的生成规则;
                 *
                 * 参数一:  Function<String, Object>,第一个泛型表示流中数据的类型,第二个泛型表示Map集合中键的数据类型
                 *         方法apply的形参:依次表示流里面的每一个数据
                 *         方法体:生成键
                 *         返回值:已经生成的键
                 *
                 * 参数二:  Function<String, Object>,第一个泛型表示流中的数据的类型,第二个泛型表示Map集合中值的数据类型
                 *         方法apply的形参:依次表示流里面的每一个数据
                 *         方法体:生成值
                 *         返回值:已经生成的值
                 * */
    .collect(Collectors.toMap(new Function<String, Integer>() {
        @Override
        public Integer apply(String s) {
            return Integer.parseInt(s.split("-")[0]);
        }
    }, new Function<String, String>() {
        @Override
        public String apply(String s) {
            return s.split("-")[1];
        }
    }));
System.out.println("map" + map);

用Lambda表达式简化

System.out.println("----------------------简化后---------------------------");
map = list1.stream()
    .filter(s -> Integer.parseInt(s.split("-")[0]) < 10)
    .collect(Collectors.toMap( s -> Integer.parseInt(s.split("-")[0]), s -> s.split("-")[1]));
System.out.println("map" + map);

注意:使用toMap方法时,流中的数据的键不能重复,否则会直接报错。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值