Stream流之最全学习总结

Stream流是java8的一大亮点,它与java.io包里面的InputStream和OutputStream是完全不同的概念。

java8中的Stream流是对集合(Collections)和数组对象功能的增强,它专注与对集合对象和数组进行非常高效的遍历操作。Stream不是集合元素,它不是数据结构,并不保存数据,它更像一个高级版本的Iteractor。原始版本的Iteractor:用户只能显示的一个一个遍历元素并对其进行操作。高级版本的Stream:用户只要给出对其包含的元素执行什么操作,比如“过滤长度大于10的字符串”,“获取每个字符串的首字母”等,Stream会隐士的在内部进行遍历并作出相应的数据转换。

Stream流可以理解为一个流水线,通过一道道工序对集合元素进行处理,加工,得到想要的元素。

一.Stream流之初体验

/**
 * @Author: chuxia0811
 * @Date: 2021/3/2 22:33
 * @Description :
 * 需求:筛选集合中所有姓孙的,名字长度为3的,并打印出来这些名字
 */
public class Demo1 {
    public static void main(String[] args) {
        List<String> names = new ArrayList<String>();
        names.add("孙大圣");
        names.add("安琪拉");
        names.add("德玛西亚");
        names.add("孙悟空");
        names.add("张三丰");
        names.add("吴孟达");
        names.add("小强");

        //一.用原始方法实现
        List<String> zlist = new ArrayList<>();
        // 筛选所有姓孙的
        for (String name : names) {
            if (name.startsWith("孙")) {
                zlist.add(name);
            }
        }
        // 筛选名字长度为3的
        List<String> result = new ArrayList<>();
        for (String name : zlist) {
            if (name.length() == 3) {
                result.add(name);
            }
        }
        //打印名字
        for (String name : result) {
            System.out.println(name);
        }

        System.out.println("=================华丽的分割线==============");
        //二:用Stream流实现
        names.stream().filter(name -> name.startsWith("孙")).filter(name -> name.length()==3).forEach(name -> System.out.println(name));
    }
}

看到上面的demo应该可以体会到Stream流惊人的效率吧?普通方式实现一个过滤打印需要十几行代码,用Stream流只需要一行就可以实现了,下面详细介绍Stream流的使用。

二:Stream流的获取方式

Stream流的获取方式:
1.单列集合:list,Set Stream 集合对象.stream();
2.双列集合:map 没有方法直接获取Stream流对象,需要将双列集合转化为单列集合,再调用.stream()方法获取流;
3.数组:使用Stream提供的静态方法of()获取。

/**
 * @Author: chuxia0811
 * @Date: 2021/3/2 23:15
 * @Description :
 */
public class Demo2 {
    public static void main(String[] args) {
        // 1.List集合
        List<String> list = new ArrayList<>();
        Stream<String> listStream = list.stream();
        //2.Set集合
        Set<String> set = new HashSet<>();
        Stream<String> streamSet = set.stream();
        //3.Map集合
        Map<String,String> map = new HashMap<>();
            //获取键对应的stream流
        Set<String> keyset = map.keySet();
        keyset.stream();
            //获取值对应的stream流
        Collection<String> value = map.values();
        value.stream();
            //获取Entry对象集合
        Set<Map.Entry<String,String>> entrySet = map.entrySet();
        entrySet.stream();

        //4.数组
        String[] str = {"a","b","c"};
        Stream<String> arrayStream = Stream.of(str);

    }
}

三:Stream流常用的方法

1.forEach方法

/**
 * @Author: chuxia0811
 * @Date: 2021/3/3 22:57
 * @Description :作用:循环,对流中的每一个元素进行遍历,将每一个元素传递给消费者对象处理
 */
public class ForEach {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        Collections.addAll(list,"迪丽热巴","唐嫣","罗晋","郝泽宇","艾伦");
        list.stream().forEach(name ->{
            System.out.println(name);
        });
    }
}

运行结果如下:

迪丽热巴
唐嫣
罗晋
郝泽宇
艾伦

2.filter方法

/**
 * @Author: chuxia0811
 * @Date: 2021/3/3 22:57
 * @Description :
 */
public class ForEach {
    public static void main(String[] args) {
        // filter作用:对流中的元素进行过滤
        List<String> list = new ArrayList<String>();
        Collections.addAll(list, "迪丽热巴", "唐嫣", "罗晋", "郝泽宇", "艾伦");
        //筛选保留名字为3位的
        list.stream().filter(name -> name.length() == 3).forEach(name -> System.out.println(name));
    }
}

运行结果如下:

郝泽宇

3.limit方法

/**
 * @Author: chuxia0811
 * @Date: 2021/3/3 23:19
 * @Description :
 */
public class LimitDemo {
    public static void main(String[] args) {
        // limit(n)作用:获取流中前n个元素,其中n>=0,n=0时输出一个空流,
        // 当n>元素总数size时会输出所有元素,当n<0时会报非法参数异常
        List<String> list = new ArrayList<String>();
        Collections.addAll(list, "迪丽热巴", "唐嫣", "罗晋", "郝泽宇", "艾伦");
        Stream<String> stream = list.stream();
        Stream<String> newStream = stream.limit(3);
        newStream.forEach(name -> System.out.println(name));
    }
}

4.skip方法

/**
 * @Author: chuxia0811
 * @Date: 2021/3/3 23:28
 * @Description :
 */
public class SkipDemo {
    public static void main(String[] args) {
        // skip方法作用:和limit相反,指跳过前n个元素放在另外一个流中
        // n < 0时会报参数非法异常; n = 0会跳过0个元素,即输出所有元素
        // n < 元素个数size时会跳过前n个元素; n > 元素个数size时会跳过所有元素,输出空流
        List<String> list = new ArrayList<String>();
        Collections.addAll(list, "迪丽热巴", "唐嫣", "罗晋", "郝泽宇", "艾伦");
        Stream<String> stream = list.stream();
        Stream<String> newStream = stream.skip(3);
        newStream.forEach(name -> System.out.println(name));
    }
}

5.map方法

/**
 * @Author: chuxia0811
 * @Date: 2021/3/4 23:22
 * @Description :
 */
public class MapDemo {
    public static void main(String[] args) {
        //map作用:遍历流中的每一个元素,将元素从一种类型转换成另外一种类型,放到新流中
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "1", "2", "3", "4", "5", "6", "7");
        Stream<Integer> stream = list.stream().map(str -> Integer.parseInt(str) + 1);
        stream.forEach(num -> System.out.println(num));
    }
}

运行如下:

2
3
4
5
6
7
8

6.concat方法

/**
 * @Author: chuxia0811
 * @Date: 2021/3/4 23:33
 * @Description :
 */
public class ConcactDemo {
    public static void main(String[] args) {
    //concact作用,合并流
        List<String> one = new ArrayList<>();
        List<String> two = new ArrayList<>();
        Collections.addAll(one, "A", "B", "C");
        Collections.addAll(two, "1", "2", "3");
        Stream<String> stream1 = one.stream();
        Stream<String> stream2 = two.stream();
        Stream<String> stream = Stream.concat(stream1, stream2);
        stream.forEach(str -> System.out.println(str));
    }
}

运行如下:

A
B
C
1
2
3

7.count方法

/**
 * @Author: chuxia0811
 * @Date: 2021/3/4 23:39
 * @Description :
 */
public class CountDemo {
    public static void main(String[] args) {
        //count方法作用:统计流中元素的个数
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "A", "B", "C", "D", "E");
        Stream<String> stream = list.stream();
        System.out.println(stream.count());
    }
}

运行结果:

5

四:Stream流使用注意事项

1.一旦调用了终结方法,流将不能再被使用,一旦调用非终结方法,原来旧的流不能再被使用了,只能用新的流进行操作。
2.终结方法:如果返回值不为Stream流,如foreach,count方法;非终结方法:如果返回值为stream流,如filter,limit,skip,map,cancat等方法。

为了解决Stream流终结不能再被使用的情况,可以收集 Stream流,即将Stream流操作后的元素放在新 的容器中(集合或数组)。

/**
 * @Author: chuxia0811
 * @Date: 2021/3/6 10:48
 * @Description :
 */
public class CollectDemo {
    /**
     * 讲解:以下1~4程序不能同时执行,流被终结了,需要注释其他的,一个个单独运行
     * 1.将Stream流结果收集到集合中
     * 收集的Stream流放在List集合中:流对象.collect(collectors.toList())
     * * 收集的Stream流放在Set集合中:流对象.collect(collectors.toSet())
     * <p>
     * 2.收集的流放到数组中
     * *流对象.toArray()
     * *流对象.toArray(数据类型::new)
     */
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "老子", "庄子", "孟子", "韩非子", "儿子");
        Stream<String> stream = list.stream();

        //1.收集流到List集合中
        List<String> newList = stream.collect(Collectors.toList());
        System.out.println(newList.size());
        for (String name : newList) {
            System.out.println(name);
        }

        //2.收集到Set集合
        Set<String> set = stream.collect(Collectors.toSet());
        System.out.println(set.size());
        for (String name : set) {
            System.out.println(name);
        }

        //3.收集到Array
        Object[] obj = stream.toArray();
        for (Object name : obj) {
            System.out.println(obj);
        }
        //4.指定类型的数组,重载的toarry方法
        String[] names = stream.toArray(String[]::new);
        for (String name : names) {
            System.out.println(name);
        }
    }
}

五:Stream流之串行与并行

/**
 * @Author: chuxia0811
 * @Date: 2021/3/6 11:14
 * @Description :
 */
public class ParalleDemo {
    public static void main(String[] args) {
        test1();
        test2();
    }

    /**
     *测试1~ 1亿的和。串行流
     */
    public static void test1(){
        Long startTime = System.currentTimeMillis();
        Long sum = LongStream.rangeClosed(0L,100000000L).sum();
        System.out.println(sum);
        Long endTime = System.currentTimeMillis();
        System.out.println("串行执行总耗时:"+(endTime-startTime));
    }

    /**
     *测试1~ 1亿的和。并行流
     */
    public static void test2(){
        Long startTime = System.currentTimeMillis();
        Long sum = LongStream.rangeClosed(0L,100000000L).parallel().sum();
        System.out.println(sum);
        Long endTime = System.currentTimeMillis();
        System.out.println("串行执行总耗时:"+(endTime-startTime));
    }
}

运行结果如下:

5000000050000000
串行执行总耗时:111
5000000050000000
串行执行总耗时:40

由此可以看出,通过parallel()获得并行流的效率是串行的好几倍,所有数据量比较大的时候建议使用并行流。如果数据量不大建议使用串行流,应为数据量小两者区别不大,创建并行流反而需要消耗资源。

六:方法的引用

1.静态方法的引用

静态方法的引用:类名::静态方法,通过类名来引用静态方法,简化Lambda表达式。

注意事项:
1.被引用的方法和函数式接口中的抽象方法必要要有相同的参数列表;
2.如果函数式接口中的抽象方法有返回值,则被引用的方法必须要有相同类型的返回值;
3.如果函数式接口中的抽象方法没有返回值,则被引用的方法中可以有也可以没有返回值。

/**
 * @Author: chuxia0811
 * @Date: 2021/3/6 14:23
 * @Description :
 */
public class StreamStaticDemo {
    public static void main(String[] args) {
        int[] arr = {45, 12, 3, 189, -12};
        // ArrayUtils::getMax 会创建一个类,实现ArrayHelper接口,再创建了一个实现类对象给arrayHelper;
        ArrayHelper arrayHelper = ArrayUtils::getMax;
        int max = arrayHelper.maxValue(arr);
        System.out.println("数组最大值为:" + max);
    }
}

@FunctionalInterface
interface ArrayHelper {
    int maxValue(int[] arr);
}

class ArrayUtils {
    public static int getMax(int[] arr) {
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        return max;
    }
}

2.对象方法的引用

对象方法的引用:对象::方法,通过对象来引用普通已存在方法,简化Lambda表达式。
注意事项同静态方法引用。

/**
 * @Author: chuxia0811
 * @Date: 2021/3/6 14:56
 * @Description :
 */
public class StreamFunDemo {
    public static void main(String[] args) {
        MyRandom myRandom = new MyRandom();
        NumHelper helper = myRandom::nextIntAtoB;
        System.out.println(helper.nexIntAtoB(100, 200));

    }
}

class MyRandom {
    public int nextIntAtoB(int a, int b) {
        Random random = new Random();
        return random.nextInt(b - a + 1) + a;
    }
}

@FunctionalInterface
interface NumHelper {
    int nexIntAtoB(int a, int b);
}

3.构造方法的引用

构造方法的引用:对象::new。

/**
 * @Author: chuxia0811
 * @Date: 2021/3/6 16:12
 * @Description :
 */
public class ConstructDemo {
    public static void main(String[] args) {
        CarFactory factory = Car::new;
        System.out.println( factory.makeCar("奔驰"));
    }
}

class Car{
    private String brand;

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Car(String brand) {
        this.brand = brand;
    }

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

@FunctionalInterface
interface CarFactory{
    Car makeCar(String brand);
}

4.特定类型方法的引用
通过类名引用非静态方法:类名::非静态方法

/**
 * @Author: chuxia0811
 * @Date: 2021/3/6 16:42
 * @Description :
 */
public class StreamFunDemoother {
    public static void main(String[] args) {
        String[] strs = {"Ba", "Ac", "De", "a", "哈哈哈"};
        Arrays.sort(strs, String::compareToIgnoreCase);
        for (String str : strs) {
            System.out.println(str);
        }
    }
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

初夏0811

你的鼓励将是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值