Loading

Java8 Stream流

Stream流

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

image-20220808103626965

1 起始操作

在 Java 8 中, 集合接口有两个方法来生成流:

  • stream() − 为集合创建串行流。
  • parallelStream() − 为集合创建并行流。

生成流

// 为集合创建串行流
Stream<String> stream = list.stream();

// 为集合创建并行流
Stream<String> stream = list.parallelStream();

2 中间操作

过滤器

public class Demo01 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素。
        List<String> list = new ArrayList<>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");
        /*
            filter()方法是中间操作,中间操作都用lambda表达式。
         */

        //需求1:把list集合中以“张”开头的元素在控制台输出。
        System.out.println("======需求1=====");
        list.stream().filter(x -> x.startsWith("张")).forEach(System.out::println);

        //需求2:把list集合中长度为3的元素在控制台输出。
        System.out.println("======需求2=====");
        list.stream().filter(x -> x.length() == 3).forEach(System.out::println);

        //需求3:把list集合中以“张”开头的,长度为3的元素在控制台输出。
        System.out.println("======需求3=====");
        //在一个过滤器中要满足两个条件。
        list.stream().filter(x -> x.startsWith("张") && x.length() == 3).forEach(System.out::println);
        System.out.println("-----");
        //用两个过滤器,先过滤出以“张”开头的元素,再过滤出长度为3的元素。
        list.stream().filter(x -> x.startsWith("张")).filter(x -> x.length() == 3).forEach(System.out::println);
    }
}

理解stream流的时候,可以顺便复习复习lambda表达式。

// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

限制、跳过

/*
    中间操作
        限制:limit()
        跳过:skip()
 */
public class Demo02 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素。
        List<String> list = new ArrayList<>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");

        //需求1:取前3个数据在控制台输出。
        System.out.println("======需求1======");
        list.stream().limit(3).forEach(System.out::println);
        //需求2:跳过3个元素,把剩下的元素在控制台输出。
        System.out.println("=====需求2=======");
        list.stream().skip(3).forEach(System.out::println);
        //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出。
        System.out.println("=====需求3======");
        //先用一个skip(2)跳过前两个元素,在剩下的元素中用limit(2)取前两个元素并输出。
        list.stream().skip(2).limit(2).forEach(System.out::println);
    }
}

合并流、去重

/*
    中间操作
        合并流:concat()------这是一个静态方法。Stream.concat()
        去重:distinct()

 */
public class Demo03 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素。
        List<String> list = new ArrayList<>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");

        //需求1:取前4个数据组成一个流。
        Stream<String> stream1 = list.stream().limit(4);
        //需求2:跳过2个数据组成一个流。
        Stream<String> stream2 = list.stream().skip(2);
        //需求3:合并需求1和需求2得到的流,并把结果在控制台输出。
        //合并流的方法concat()是一个静态方法。
        Stream.concat(stream1, stream2).forEach(System.out::println);

        //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复。
        Stream.concat(stream1, stream2).distinct().forEach(System.out::println);
    }
}

排序

/*
    中间操作
        自然排序:sorted()
        用比较器比较排序:sorted(Comparator comparator)
 */
public class Demo04 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素。
        List<String> list = new ArrayList<>();
        list.add("linqingxia");
        list.add("zhangmanyu");
        list.add("wangzuxian");
        list.add("liuyan");
        list.add("zhangming");
        list.add("zhangwuji");

        //需求1:按照字母顺序把数据在控制台输出。
        System.out.println("====需求1====");
        list.stream().sorted().forEach(System.out::println);
        //需求2:按照字符串长度把数据在控制台输出。
        System.out.println("====需求2====");
        //前面-后面:从小到大    后面-前面:从大到小
        list.stream().sorted((s1, s2) -> s1.length() - s2.length()).forEach(System.out::println);
        //需求3:先按照长度,再按照字母顺序排序。
        System.out.println("====需求3====");
        list.stream().sorted((s1, s2) -> {
            int sort1 = s1.length() - s2.length();
            int sort2 = sort1 == 0 ? s1.compareTo(s2) : sort1;
            return sort2;
        }).forEach(System.out::println);
    }
}

返回此流元素组成的流

/*
    中间操作
        返回此流元素组成的流:map()
        IntSteam mapToInt()   返回一个IntSteam类型的结果
 */
public class Demo05 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("10");
        list.add("20");
        list.add("30");
        list.add("40");
        list.add("50");

        //需求:将集合中的字符串数据转换为整数之后在控制台输出。
        System.out.println("====需求1====");
        list.stream().map(x->Integer.parseInt(x)).forEach(System.out::println);
        //以上方法可以改进。
        System.out.println("====需求1改进====");
        list.stream().map(Integer::parseInt).forEach(System.out::println);
        //以上方法还可以改进。
        System.out.println("====需求1再改进====");
        //用第3个
        list.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
        //求和
        int sum = list.stream().mapToInt(Integer::parseInt).sum();
        System.out.println("求和:" + sum);
    }
}

3 终结操作

输出

/*
    终结操作
        输出:forEach()
        返回流中的元素数:count()
 */
public class Demo06 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素。
        List<String> list = new ArrayList<>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");

        //需求1:把集合中的元素在控制台输出。
        System.out.println("====需求1====");
        list.stream().forEach(System.out::println);
        //需求2:统计集合中有几个以“张”开头的元素,并把统计结果在控制台输出。
        System.out.println("====需求2====");
        long count = list.stream().filter(x -> x.startsWith("张")).count();
        System.out.println(count);
    }
}

收集操作

map只是把一个新的流转换为一个新的流,而collect的把流转换为集合。

/*
    Stream流的收集操作

 */
public class Demo08 {
    public static void main(String[] args) {
        //创建List集合对象
        List<String> list = new ArrayList<>();
        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        //需求1:得到名字为3个字的流
        Stream<String> stream = list.stream().filter(x -> x.length() == 3);
        //需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历。
        List<String> collectList = stream.collect(Collectors.toList());
        System.out.println("=====List=====");
        for (String string : collectList) {
            System.out.println(string);
        }

        //创建Set集合对象。
        Set<Integer> set = new HashSet<>();
        set.add(10);
        set.add(20);
        set.add(30);
        set.add(40);
        //需求3:得到大于25的流
        Stream<Integer> integerStream = set.stream().filter(x -> x > 25);
        //需求4:把使用Stream流操作完毕的数据收集到Set集合中并遍历。
        Set<Integer> collectSet = integerStream.collect(Collectors.toSet());
        System.out.println("=====Set=====");
        //Set集合是无序的,输出无序。
        for (Integer integer : collectSet) {
            System.out.println(integer);
        }

        //定义一个字符串数组。
        String string[] = {"林青霞,1", "张曼玉,2", "王祖贤,3", "柳岩,4"};
        //需求5:得到字符串中数据大于2的流。
        Stream<String> stringStream = Stream.of(string).filter(x -> Integer.parseInt(x.split(",")[1]) > 2);
        //需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,序号作值。
        Map<String, Integer> integerMap = stringStream.collect(Collectors.toMap(x -> x.split(",")[0], x -> Integer.parseInt(x.split(",")[1])));
        Set<String> ketSet = integerMap.keySet();
        System.out.println("=====Map=====");
        for (String str : ketSet) {
            Integer value = integerMap.get(str);
            System.out.println(str + "=" + value);
        }
    }
}

4 练习

/*
    Stream流的练习
        现在有两个 ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作
        1.男演员只要名字为3个字的前三人
        2.女演员只要姓林的,井且不要第一个
        3.把过滤后的男演员姓名和女演员姓名合并到一起
        4.把上一步操作后的元素作为构造方法的参数创建演员对象遍历数据
            演员类Actor已经提供,里面有一个成员变量,一个带参造方法,以及成员变量对应的 get/set方法
 */
public class Demo01 {
    public static void main(String[] args) {
        //男演员集合
        List<String> manList = new ArrayList<>();
        manList.add("周润发");
        manList.add("成龙");
        manList.add("刘德华");
        manList.add("吴京");
        manList.add("周星驰");
        manList.add("李连杰");
        //女演员集合
        List<String> womanList = new ArrayList<>();
        womanList.add("林心如");
        womanList.add("张曼玉");
        womanList.add("林青霞");
        womanList.add("柳岩");
        womanList.add("林志玲");
        womanList.add("王祖贤");

        System.out.println("================方法1================");
        Stream<String> manListStream = manList.stream().filter(name -> name.length() == 3).limit(3);
        
        Stream<String> womanListStream = womanList.stream().filter(name -> name.startsWith("林")).skip(1);
        
        Stream<String> concatStream = Stream.concat(manListStream, womanListStream);
        
        concatStream.map(name -> new Actor(name)).forEach(System.out::println);
        // concatStream.map(Actor::new).forEach(System.out::println);
        
        System.out.println("================方法2================");
        Stream.concat(manList.stream().filter(x -> x.length() == 3).limit(3)
                , womanList.stream().filter(x -> x.startsWith("林")).skip(1))
                .map(Actor::new)
                .forEach(System.out::println);
    }
}

class Actor {
    private String name;

    public Actor() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Actor{" +
                "name='" + name + '\'' +
                '}';
    }
}

参考资料:Java 8 Stream | 菜鸟教程 (runoob.com)

posted @ 2022-08-08 14:54  KledKled  阅读(9)  评论(0编辑  收藏  举报