Stream流

Stream流

Stream流算是Java简化步骤的最基础部分

Stream流通过和Lambda,方法引用,函数式常用接口等相结合,简化数据的存放,筛选和输出

Stream流的使用

Stream流的使用分为三个步骤:

  • 生成流
    • 通过数据源(集合,数组)生成流
    • 例如:list.stream()
  • 中间操作
    • 一个流后面可以跟零个或无限个中间操作,其目的是打开流做出某种程度的过滤或映射,然后返回一个新的流
    • 例如:filter()
  • 终结操作
    • 一个流只能有一个终结操作,操作执行后,流被使用,无法再被操作
    • 例如:forEach()

下面我们先给出一个Stream流的使用案例

需求:

  • 我们想在下列集合中得到姓刘且长度为2的名字并输出

代码如下:

import java.util.ArrayList;
import java.util.stream.Stream;

public class Demo1 {
    public static void main(String[] args) {
        //首先创造集合
        ArrayList<String> arr = new ArrayList<>();

        //加入对象
        arr.add("刘禅");
        arr.add("刘备");
        arr.add("孙尚香");
        arr.add("诸葛亮");
        arr.add("刘亦菲");

        //我们的要求是从arr中取出姓刘且两个字的名字
        //如果我们采用正常方法,需要采用到for循环一次一次遍历

        //这里我们直接给出stream流方法(注意:Stream流方法通常与Lambda以及方法引用实现)
        arr.stream().filter(s -> s.startsWith("刘")).filter(s -> s.length() == 2).forEach(System.out::println);
    }
}

Stream流的生成方法

Stream流常见生成方法:

  • Collection体系的集合可以使用默认方法Stream()生成流
  • Map体系的集合只能够间接的生成流
  • 数组只能通过Stream类的固定of方法生成流

下面给出示例代码:

import java.util.*;
import java.util.stream.Stream;

public class Demo2 {
    public static void main(String[] args) {
        //Collection集合生成Stream流可直接生成
        List<String> list = new ArrayList<>();
        Stream<String> listStream = list.stream();

        Set<String> set = new HashSet<>();
        Stream<String> setStream = set.stream();

        //Map集合生成Stream流需要间接生产
        Map<String,Integer> map = new HashMap<>();
        Stream<String> KeyStream = map.keySet().stream();
        Stream<Integer> valueStream = map.values().stream();
        Stream<Map.Entry<String,Integer>> mapStream = map.entrySet().stream();

        //数组需要通过Stream的Static方法of来生产流
        String[] strArray = {"Hello","World","Java"};
        Stream<String> strStream = Stream.of(strArray);
        Stream<Integer> intStream = Stream.of(10,20,30);
    }
}

Stream流的中间操作方法

大致方法如下:

方法名 说明
Stream filter(Predicate predicate) 用于对流中的数据进行过滤
Stream limit(long maxSize) 返回此流中的元素组成的流,截取前指定参数个数的数据
Stream skip(long n) 跳过指定参数个数的数据,返回由该流的剩余元素组成的流
static Stream concat(Stream a,Stream b) 合并a和b两个流组成一个流
Stream distinct() 返回该流的不同元素组成的流
Stream sorted() 返回由此流的元素组成的流,按照自然顺序排序
Stream sorted(Comparator comparator) 返回由此流的元素组成的流,按照Comparator要求排序
Stream map(Function mapper) 返回由给定函数应用于此类的元素的结果组成的流
IntStream Stream mapToInt(Function mapper) 返回一个IntStream其中包含将给定函数应用于此流的元素的结果

下面给出上述方法的示例代码:

import java.util.ArrayList;
import java.util.stream.Stream;

public class Demo3 {
    public static void main(String[] args) {
        //首先创造集合
        ArrayList<String> arr = new ArrayList<>();

        //加入对象
        arr.add("刘禅");
        arr.add("刘备");
        arr.add("孙尚香");
        arr.add("诸葛亮");
        arr.add("刘亦菲");

        //以下是filter方法讲解

        //获得所有姓刘的集合并输出
        arr.stream().filter((String s) -> s.startsWith("刘")).forEach(System.out::println);
        System.out.println("-----------");

        //获得所有三个字的名字的集合并输出
        arr.stream().filter((String s) -> s.length() == 3).forEach(System.out::println);
        System.out.println("-----------");

        //获得所有姓刘的且名字是三个字的集合并输出
        arr.stream().filter(s -> s.startsWith("刘")).filter(s -> s.length() == 2).forEach(System.out::println);
        System.out.println("-----------");

        //以下是limit和skip方法讲解

        //我们只要前两个名字输出
        arr.stream().limit(2).forEach(System.out::println);
        System.out.println("-----------");

        //我们跳过前两个名字输出
        arr.stream().skip(2).forEach(System.out::println);
        System.out.println("-----------");

        //我们跳过前两个名字然后输出两个名字
        arr.stream().skip(2).limit(2).forEach(System.out::println);
        System.out.println("-----------");

        //以下是concat和distinct方法的讲解

        //concat是static方法,我们需要两个Stream流对象
        Stream<String> s1 = arr.stream().limit(4);
        Stream<String> s2 = arr.stream().skip(2);
        Stream<String> s3 = arr.stream().skip(3);

        //然后我们调用concat方法,要由Stream类调用
        //Stream.concat(s1,s2).forEach(System.out::println);
        //System.out.println("-----------");

        //因为我们concat方法中获得的元素有重复元素,我们需要用distinct方法去除
        Stream.concat(s1,s3).distinct().forEach(System.out::println);
        System.out.println("-----------");
    }
}
import java.util.ArrayList;

public class Demo4 {
    public static void main(String[] args) {
        //首先创造集合
        ArrayList<String> arr = new ArrayList<>();

        //我们因为演示sorted()方法,所有这里数据采用拼音
        arr.add("zhangchen");
        arr.add("zhangmanyu");
        arr.add("liudehuada");
        arr.add("sunce");
        arr.add("daqiao");

        //首先我们尝试自然排序
        arr.stream().sorted().forEach(System.out::println);
        System.out.println("-----------");

        //然后我们按照长度排序(注意:这里仅仅按照长度排序,当长度相同时其他数据随机排序)
        arr.stream().sorted((s1,s2) -> s1.length()-s2.length()).forEach(System.out::println);
        System.out.println("-----------");

        //我们创造一个按长度排序,当长度相同时,我们按自然排序
        arr.stream().sorted((s1,s2) -> {
            int num = s1.length()-s2.length();
            int num2 = num==0?s1.compareTo(s2):num;
            return num2;
        }).forEach(System.out::println);
        System.out.println("-----------");
    }
}
import java.util.ArrayList;

public class Demo5 {
    public static void main(String[] args) {
        //首先创造集合
        ArrayList<String> arr = new ArrayList<>();

        //我们添加元素
        arr.add("10");
        arr.add("20");
        arr.add("30");
        arr.add("40");
        arr.add("50");

        //我们采用map方法转换类型并输出
        arr.stream().map((String s) -> Integer.parseInt(s)).forEach(System.out::println);
        System.out.println("---------");

        //我们也可以采用mapToInt方法转换
        arr.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
        System.out.println("---------");

        //mapToInt方法中可以采用sum()方法获得总和
        int sum = arr.stream().mapToInt(Integer::parseInt).sum();
        System.out.println(sum);
        System.out.println("---------");
    }
}

Stream流的终结操作方法

大致方法如下:

方法名 说明
void forEach(Consumer action) 对此流的每个元素执行操作
long count() 返回此流中的元素数

下面给出示例代码:

import java.util.ArrayList;

public class Demo6 {
    public static void main(String[] args) {
        //首先创造集合
        ArrayList<String> arr = new ArrayList<>();

        //加入对象
        arr.add("刘禅");
        arr.add("刘备");
        arr.add("孙尚香");
        arr.add("诸葛亮");
        arr.add("刘亦菲");

        //我们直接测试输出
        arr.stream().forEach(System.out::println);

        //我们统计姓刘的人数
        long num = arr.stream().filter(s -> s.startsWith("刘")).count();
        System.out.println(num);
    }
}

Stream流收集操作

对数据使用Stream方法变成流后,我们该如何回收到集合中呢?

Java提供给了我们collect方法:

  • R collect(Collector collector)
  • 但这个收集方法的参数是一个接口

工具类Collectiors提供了具体的收集方法:

  • public static Collector toList():把元素收集到List集合中
  • public static Collector toSet():把元素收集到Set集合中
  • public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中

下面给出示例代码:

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Demo1 {
    public static void main(String[] args) {
        //创造集合1
        ArrayList<String> arrayList1 = new ArrayList<>();
        arrayList1.add("bandecan");
        arrayList1.add("heimao");
        arrayList1.add("miluo");
        arrayList1.add("mikumaster");

        //针对集合1获得长度大于6的names
        Stream<String> stream1 = arrayList1.stream().filter(s -> s.length()>6);

        //把stream1的数据转换为List集合
        List<String> List1 = stream1.collect(Collectors.toList());
        for(String s : List1){
            System.out.println(s);
        }


        //创造集合2
        Set<Integer> set = new HashSet<>();
        set.add(25);
        set.add(20);
        set.add(30);
        set.add(35);

        //针对集合2获得年龄大于28的ages
        Stream<Integer> stream2 = set.stream().filter(age -> age > 28);

        //把Stream2的数据转化为Set集合
        Set<Integer> ages = stream2.collect(Collectors.toSet());
        for (int age : ages){
            System.out.println(age);
        }


        //创造集合3
        String[] strArrays = {"胡桃,20","可莉,10","钟离,25"};

        //针对集合3获得年龄大于18的String
        Stream<String> stream3 = Stream.of(strArrays).filter(s -> Integer.parseInt(s.split(",")[1])>18);

        //把stream3的数据转化为Map集合
        Map<String,Integer> map = stream3.collect(Collectors.toMap((String s) -> s.split(",")[0], (String s) -> Integer.parseInt(s.split(",")[1])));
        Set<String> keySet = map.keySet();
        for(String key : keySet){
            System.out.println(key + ":" + map.get(key));
        }
    }
}

案例:Stream流的练习

条件:

  • 我们给出两个ArrayList集合,分别储存6名男生,6名女生的名称
  • 我们给出学生类Actor,里面有name和构造方法

需求:

  • 男生只要名字为3个字的前三人
  • 女生只要姓小的,且不要第一个
  • 把过滤后的男生女生合并到一起
  • 把合并后的名字做参数创造学生类对象并输出

下面给出示例代码:

import java.util.ArrayList;
import java.util.stream.Stream;

public class ActorDemo {
    public static void main(String[] args) {
        //我们创建集合
        ArrayList<String> manList = new ArrayList<>();
        manList.add("黑猫子");
        manList.add("米洛");
        manList.add("白的肾");
        manList.add("昂扣挼的");
        manList.add("卡慕瓜");
        manList.add("与山鸭");

        ArrayList<String> womanList = new ArrayList<>();
        womanList.add("哈娜");
        womanList.add("小卷");
        womanList.add("小卡");
        womanList.add("子音");
        womanList.add("小沐");
        womanList.add("米神");

        //第一步:男演员只要名字为三个字的前三人
        Stream<String> manListSelect = manList.stream().filter(s -> s.length() == 3).limit(3);

        //第二步:女演员只要姓小的且不要第一个
        Stream<String> womanListSelect = womanList.stream().filter(s -> s.startsWith("小")).skip(1);

        //第三步:将两个合并在一起
        Stream<String> lastList = Stream.concat(manListSelect, womanListSelect);

        //第四步:把上一步所有元素参数创造对象并遍历
        lastList.forEach(s -> {
            Actor actor = new Actor(s);
            System.out.println(actor.name);
        });
    }
}
public class Actor {
    public String name;

    public Actor(String name){
        this.name = name;
    }
}

结束语

好的,关于Stream流我们就讲解到这里

posted @ 2022-07-06 15:32  秋落雨微凉  阅读(87)  评论(0编辑  收藏  举报