Stream流

1.概述
在Java 8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端。

2.获取流方式
java.util.stream.Stream 是Java 8新加入的最常用的流接口。(这并不是一个函数式接口。)

获取一个流非常简单,有以下几种常用的方式:
所有的 Collection 集合都可以通过 stream 默认方法获取流;
Stream 接口的静态方法 of 可以获取数组对应的流。

3.常用方法
forEach : 逐一处理
虽然方法名字叫 forEach ,但是与for循环中的“for-each”昵称不同,该方法并不保证元素的逐一消费动作在流中是被有序执行的。
void forEach(Consumer<? super T> action);

package liu;

import java.util.function.Consumer;
import java.util.stream.Stream;

public class Demo01 {
    public static void main(String[] args) {
        Stream<String> str = Stream.of("大娃","二娃","三娃","四娃","五娃","六娃","七娃","爷爷","蛇精","蝎子精");

/*        str.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/

/*        str.forEach((String s) -> {
            System.out.println(s);
        });*/

        str.forEach((s) -> System.out.println(s));
    }
}

filter:过滤

package liu;

import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class Demo02 {
    public static void main(String[] args) {
        Stream<String> str = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精");
        //匿名内部类写法
/*        str.filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("娃");
            }
        }).forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/

        //表达式写法
        str.filter( s ->
           s.contains("娃")
        ).forEach(s -> System.out.println(s));
    }
}

count:统计个数
正如旧集合 Collection 当中的 size 方法一样,流提供 count 方法来数一数其中的元素个数:
long count();
该方法返回一个long值代表元素个数(不再像旧集合那样是int值)。基本使用:

package liu;

import java.util.stream.Stream;

public class Demo03 {
    public static void main(String[] args) {
        Stream<String> str = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精");

        long num = str.count();

        System.out.println(num);
    }
}

limit:取用前几个
limit 方法可以对流进行截取,只取用前n个。方法签名:
Stream limit(long maxSize):获取Stream流对象中的前n个元素,返回一个新的Stream流对象

参数是一个long型,如果集合当前长度大于参数则进行截取;否则不进行操作。

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

Stream skip(long n): 跳过Stream流对象中的前n个元素,返回一个新的Stream流对象

如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流。

package liu;

import java.util.stream.Stream;

public class Demo04 {
    public static void main(String[] args) {
        Stream<String> str = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "蛇精", "蝎子精");

        Stream<String> s1 = str.limit(7);

        Stream<String> s2 = s1.skip(3);

        s2.forEach((s) -> System.out.println(s));
    }
}

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

static Stream concat(Stream<? extends T> a, Stream<? extends T> b): 把参数列表中的两个
Stream流对象a和b,合并成一个新的Stream流对象

备注:这是一个静态方法,与 java.lang.String 当中的 concat 方法是不同的。

package liu;

import java.util.stream.Stream;

public class Demo05 {
    public static void main(String[] args) {
        Stream<String> s1 = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃");
        Stream<String> s2 = Stream.of("爷爷", "蛇精", "蝎子精");

        Stream<String> s3 = Stream.concat(s1, s2);

        s3.forEach((name) -> System.out.println(name));

    }
}

4.综合案例
传统方式:

package liu;

import java.util.ArrayList;
import java.util.List;

/*1. 第一个队伍只要名字为3个字的成员姓名;
2. 第一个队伍筛选之后只要前3个人;
3. 第二个队伍只要姓张的成员姓名;
4. 第二个队伍筛选之后不要前2个人;
5. 将两个队伍合并为一个队伍;
6. 打印整个队伍的姓名信息。*/

public class Demo06 {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("老子");
        one.add("庄子");
        one.add("孙子");
        one.add("洪七公");

        //第一个队伍只要名字为3个字的成员姓名;
        ArrayList<String> one1 = new ArrayList<>();
        for (String a:one) {
            if (a.length() == 3){
                one1.add(a);
            }
        }

        //第一个队伍筛选之后只要前3个人
        ArrayList<String> one2 = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            one2.add(one1.get(i));
        }


        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("张三丰");
        two.add("赵丽颖");
        two.add("张二狗");
        two.add("张天爱");
        two.add("张三");

        //第二个队伍只要姓张的成员姓名
        ArrayList<String> two1 = new ArrayList<>();
        for (String a:two) {
            if (a.startsWith("张")){
                two1.add(a);
            }
        }

        //第二个队伍筛选之后不要前2个人
        ArrayList<String> two2 = new ArrayList<>();
        for (int i = 2; i < two1.size() ; i++) {
            two2.add(two1.get(i));
        }

        //将两个队伍合并为一个队伍
        ArrayList<String> list = new ArrayList<>();
        list.addAll(one2);
        list.addAll(two2);

        //打印整个队伍的姓名信息。
        for (String b:list) {
            System.out.println(b);
        }
    }
}

Stream流的方式:

package liu;

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

/*1. 第一个队伍只要名字为3个字的成员姓名;
2. 第一个队伍筛选之后只要前3个人;
3. 第二个队伍只要姓张的成员姓名;
4. 第二个队伍筛选之后不要前2个人;
5. 将两个队伍合并为一个队伍;
6. 打印整个队伍的姓名信息。*/
public class Demo07 {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("老子");
        one.add("庄子");
        one.add("孙子");
        one.add("洪七公");
        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("张三丰");
        two.add("赵丽颖");
        two.add("张二狗");
        two.add("张天爱");
        two.add("张三");

        ArrayList<String> list = new ArrayList<>();
        Stream.concat(
                one.stream().filter(name -> name.length() == 3).limit(3),
                two.stream().filter(name -> name.startsWith("张")).skip(2)
                ).forEach(name -> System.out.println(name));
    }
}