前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java知识点——Stream流

Java知识点——Stream流

作者头像
用户7073689
发布2020-03-23 14:55:59
4670
发布2020-03-23 14:55:59
举报
文章被收录于专栏:青柠小鱼青柠小鱼

Stream

1. Stream流
1.1. Stream流引入
代码语言:javascript
复制
	Stream流完全不是I/O流,按照流水线处理方式来考虑代码中的思想。
	JDK1.8 之后,我们拥有了Lambda表达式,让代码的中心偏向解决实际问题,直到重点,可以提高效率。
	Stream流中使用了大量Lambda表达式,利用Lambda操作方式,提供开发效率
1.2 传统遍历方式和Stream类处理方式对比
代码语言:javascript
复制
package com.qfedu.a_stream;

import java.util.ArrayList;

/**
 * 操作集合处理集合
 *      操作过程中创建了多个ArrayList,但是这些ArrayList都是过客,
 *      不涉及到程序的核心,这里会导致资源的浪费。
 * @author Anonymous 2020/3/12 9:56
 */
public class Demo2 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        list.add("宫保鸡丁");
        list.add("酱牛肉");
        list.add("羊肉串");
        list.add("烤羊排");
        list.add("羊肉汤");
        list.add("驴肉火烧");

        // 第一步: 对List进行过程,找出list中保存元素带有肉的,保存到另一个集合中
        ArrayList<String> list1 = new ArrayList<>();
        for (String s : list) {
            if (s.contains("肉")) {
                list1.add(s);
            }
        }

        // 第二步: 找出菜名长度==3的,保存到另一个集合中
        ArrayList<String> list2 = new ArrayList<>();
        for (String s : list1) {
            if (3 == s.length()) {
                list2.add(s);
            }
        }

        // 第三步:遍历展示对应的数据
        for (String s : list2) {
            System.out.println(s);
        }


    }
}
代码语言:javascript
复制
package com.qfedu.a_stream;

import java.util.ArrayList;

/**
 * 操作集合处理集合
 *      采用Stream流方式
 *
 * @author Anonymous 2020/3/12 9:56
 */
public class Demo2 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        list.add("宫保鸡丁");
        list.add("酱牛肉");
        list.add("羊肉串");
        list.add("烤羊排");
        list.add("羊肉汤");
        list.add("驴肉火烧");

        /*
        采用Stream流方式来处理
        直观角度可以发现,这里Stream流处理方式可以简化代码逻辑,
        更侧重于操作的重点

        第一步: 对List进行过程,找出list中保存元素带有肉的,
        第二步: 找出菜名长度==3的
        第三步:遍历展示对应的数据
        */
        list.stream()
                .filter(s->s.contains("肉"))
                .filter(s -> 3 == s.length())
                .forEach(s -> System.out.println(s));

    }
}
1.3 Stream流对应的思想
请你忘掉原先的IO流思想

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FQC4twIB-1584855460869)(img/流水线引入Stream思想.png)]

代码语言:javascript
复制
流水线:
	原材料从头到尾只会占用一份空间,中间的过程中不会占用空间。最后生成一个结果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uArJZR7s-1584855460870)(img/Stream流模型图例.png)]

代码语言:javascript
复制
Stream流有一些特征:
	1. 带有很多Stream流操作的方法, filter,limit,map,sorted,skip...这些方法大多是都会使用到函数式接口,那就意味着有lambda表达式
	2. 整个Stream流模型操作过程中,只有执行到count,foreach这些方法,操作真正的执行中的模型,如果不存在结果导向,中间的所有操作是无效的,这里得益于Lambda表达式的延后性
	3. Stream流是存在一定的管道性 Pipelining 流水线
1.4 获取Stream流
代码语言:javascript
复制
java.util.stream.Stream<T> JDK1.8的新特征
	1. 所有的Collection<T>集合都有对应的Stream();
	2. 可以通过Stream类中的static Stream of()获取
		static Stream<T> of(T... t);
		static Stream<T> of(T t);		
代码语言:javascript
复制
package com.qfedu.b_streamget;

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

/**
 * Stream流获取方式
 *      1. Collection集合
 *      2. Map双边队列
 *      3. 数组
 *
 * @author Anonymous 2020/3/12 11:16
 */
public class Demo1 {
    public static void main(String[] args) {
        // List接口获取对应的Stream流类对象
        List<String> list = new ArrayList<>();
        // 根据list保存元素的类型来约束对应的Stream流对象操作所需类型
        Stream<String> stream = list.stream();

        // 通过Set集合获取对应Stream流对象
        HashSet<String> set1 = new HashSet<>();
        Stream<String> stream1 = set1.stream();

        HashMap<String, String> map = new HashMap<>();
        // Map双边队列中所有键对应的Set集合
        Set<String> keySet = map.keySet();
        Stream<String> stream2 = keySet.stream();

        // Map双边队列中所有value对应的Collection集合
        Collection<String> values = map.values();
        Stream<String> stream3 = values.stream();

        // map中有一个方法,可以获取所有键值对类型的Set集合
        // Entry ==> 键值对,是Map接口的一个成员接口
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        // 获取Map键值对集合的Stream流对象
        Stream<Map.Entry<String, String>> stream4 = entrySet.stream();

        // 使用不定长参数获取对应的Stream流对象
        // Stream类内的静态方法of,更多的是用于数组操作提供Stream流对象
        Stream<String> stringStream = Stream.of("酱牛肉", "羊肉抓饭", "羊肉汤", "羊蝎子");

        String[] arr = {"黄河大鲤鱼", "方中山胡辣汤", "萧记烩面", "蔡记蒸饺", "葛记焖饼"};
        Stream<String> arrStream = Stream.of(arr);

        // 不建议这样使用!!!
        ArrayList<String> list1 = new ArrayList<>();
        Stream<ArrayList<String>> list11 = Stream.of(list1);

    }
}
1.5 Stream常用方法
代码语言:javascript
复制
延迟方法:
	返回值类型依然是Stream接口本身,并没有影响我们操作真正的资源
	允许链式操作,
	例如
		filter(XXX).limit(XXX).sorted(XXX).
终结方法:
	返回值类型不是Stream接口本身,要么处理数据,要么返回其他类型数据,并且不再支持Stream流对象链式操作,count,foreach
1.5.1 foreach方法【终结方法】
代码语言:javascript
复制
void foreach(Consumer<? super T> action);
/*
终结方法:
	需要一个Consumer接口进行操作处理,消耗一个数据
	Consumer接口是一个【函数式接口】那就可以使用Lambda表达式
	Consumer接口中方法是
		void accept(T t);
*/
代码语言:javascript
复制
package com.qfedu.c_streamfunction;

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

/**
 * Stream流foreach方法使用
 *
 * @author Anonymous 2020/3/12 11:39
 */
public class Demo1 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("蛋炒饭");
        list.add("虎皮青椒");
        list.add("手撕包菜");
        list.add("鲱鱼罐头");

        // 得到List对应的Stream流对象
        Stream<String> stream = list.stream();

        /*
        Stream<String> Stream流,这里操作的是String类型
            匿名内部类的匿名对象作为方法的参数,曾经多么厉害,现在是有点low
         */
        stream.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });

        // 这里需要的参数是Consumer函数式接口,完成可以使用Lambda表达式完成
        stream.forEach(string -> System.out.println(string));

        // 我们在哪里见过??? 方法引用
        stream.forEach(System.out::println);
    }
}
1.5.2 filter方法
代码语言:javascript
复制
Stream<T> filter(Predicate<? super T> condition);
/*
	filter是过滤方式,需要的参数是Predicate接口,Predicate是一个函数式接口,可以直接使用Lambda表达运行。
	这里返回值类型是Stream类对象,是经过过滤之后的Stream类型,可以进行链式操作
	Predicate接口中需要实现的方法
		boolean test(T t);
*/
代码语言:javascript
复制
package com.qfedu.c_streamfunction;

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

/**
 * Stream流对象filter方法演示
 *
 * @author Anonymous 2020/3/12 11:50
 */
public class Demo2 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        list.add("擀面皮");
        list.add("肉夹馍");
        list.add("冰峰");
        list.add("水盆羊肉");

        Stream<String> stringStream = list.stream().filter(s -> s.length() >= 3);
        stringStream.forEach(System.out::println);

        Stream<String> stringStream1 = stringStream.filter(s -> 4 == s.length());
        stringStream1.forEach(System.out::println);
        /*
        Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
            at java.util.stream.AbstractPipeline.<init>(AbstractPipeline.java:203)
            at java.util.stream.ReferencePipeline.<init>(ReferencePipeline.java:94)
            at java.util.stream.ReferencePipeline$StatelessOp.<init>(ReferencePipeline.java:618)
            at java.util.stream.ReferencePipeline$2.<init>(ReferencePipeline.java:163)
            at java.util.stream.ReferencePipeline.filter(ReferencePipeline.java:162)
            at com.qfedu.c_streamfunction.Demo2.main(Demo2.java:23)
         */
    }
}

stream has already been operated upon or closed

为何会出现这个错误?

因为调用终结方法后,Stream流已经被销毁,所以不能再对Stream流进行操作。

1.5.3 map方法
代码语言:javascript
复制
<R> Stream<R> map(Function<? super T, ? super R> fun);
/*
类型转换操作,得到的一个转换之后数据类型的Stream流对象
这里需要的参数是Function函数式接口,
	R apply(T t);
	T类型的数据转换成R类型数据
*/
代码语言:javascript
复制
package com.qfedu.c_streamfunction;

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

/**
 * Stream流 map映射方法演示
 *
 * @author Anonymous 2020/3/12 14:39
 */
public class Demo3 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        list.add("1,骚磊,16");
        list.add("2,骚杰,66");
        list.add("3,老黑,46");
        list.add("4,老付,36");
        list.add("5,污云,56");
        list.add("6,帅栋,26");

        System.out.println(list);

        Stream<Person> personStream = list.stream().map(s -> {
            String[] split = s.split(",");
            Person person = new Person();

            person.setId(Integer.parseInt(split[0]));
            person.setName(split[1]);
            person.setAge(Integer.parseInt(split[2]));

            return person;
        });

        personStream.forEach(System.out::println);
    }
}
1.5.4 count方法【终结方法】
代码语言:javascript
复制
long count();
/*
返回当前Stream流对象中有多少个元素
类似有Collection接口下的size(). String的length();
【终结方法】
	一旦执行Stream流对象被关闭
*/
代码语言:javascript
复制
package com.qfedu.c_streamfunction;

import java.util.ArrayList;

/**
 * Stream流对象 count方法演示【终结方法】
 *
 * @author Anonymous 2020/3/12 14:50
 */
public class Demo4 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        list.add("擀面皮");
        list.add("肉夹馍");
        list.add("冰峰");
        list.add("水盆羊肉");

        // 当前Stream流对象中有多少个元素,终结方法
        long count = list.stream().filter(s -> s.length() >= 3).count();
        System.out.println(count);
    }
}
1.5.5 limit方法
代码语言:javascript
复制
Stream<T> limit(long maxSize);
/*
对于当前Stream流对象操作的数据进行限制操作,限制个数到maxSize
例如:
	Stream流中保存的有10个元素,limit 5 ==> 前五个元素
*/
代码语言:javascript
复制
package com.qfedu.c_streamfunction;

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

/**
 * Stream流对象 limit方法
 *
 * @author Anonymous 2020/3/12 15:03
 */
public class Demo5 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        list.add("红旗");
        list.add("领克");
        list.add("吉利");
        list.add("比亚迪");
        list.add("长安");
        list.add("五菱宏光");

        Stream<String> stream = list.stream();
        // @throws IllegalArgumentException if {@code maxSize} is negative
        stream.limit(5).forEach(System.out::println);
    }
}
1.5.6 skip方法
代码语言:javascript
复制
Stream<T> skip(long n);
/*
返回值依然是一个Stream流对象,这里跳过当前Stream流对象前n个元素
*/
代码语言:javascript
复制
package com.qfedu.c_streamfunction;

import java.util.ArrayList;

/**
 * Stream流对象 skip方法
 *
 * @author Anonymous 2020/3/12 15:10
 */
public class Demo6 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        list.add("陆巡");
        list.add("高R");
        list.add("RS7");
        list.add("s4");
        list.add("霸道");
        list.add("道奇");

        list.stream().skip(2).forEach(System.out::println);
    }
}
1.5.7 concat方法
代码语言:javascript
复制
static Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) 
/*
拼接两个Stream流对象,是一个静态方法,得到新的Stream流对象
*/
代码语言:javascript
复制
package com.qfedu.c_streamfunction;

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

/**
 * Stream流 静态成员方法 concat方法
 *
 * @author Anonymous 2020/3/12 15:15
 */
public class Demo7 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        list.add("红旗");
        list.add("领克");
        list.add("吉利");
        list.add("比亚迪");
        list.add("长安");
        list.add("五菱宏光");

        ArrayList<String> list1 = new ArrayList<>();

        list1.add("陆巡");
        list1.add("高R");
        list1.add("RS7");
        list1.add("s4");
        list1.add("霸道");
        list1.add("道奇");

        // 获取到两个Stream流,其中保存的数据类型都是String类型
        Stream<String> stream = list.stream();
        Stream<String> stream1 = list1.stream();

        Stream<String> concat = Stream.concat(stream, stream1);

       concat.forEach(System.out::println);

    }
}
1.5.8 原始操作方式和Stream流方式对比
代码语言:javascript
复制
1. 一个String类型的字符串集合,"1,骚磊,16"
2. 过滤没有5的数据
3. 跳过前三个数据
4. 限制得到前5个数据
5. 两个String类型集合字符串合并
6. 转换成Person类型
7. 展示数据
代码语言:javascript
复制
package com.qfedu.c_streamfunction;

import java.util.ArrayList;

/**
 * 采用原始的List集合方式操作
 *   1. 一个String类型的字符串集合,"1,骚磊,16"
 *   2. 过滤没有5的数据
 *   3. 跳过前三个数据
 *   4. 限制得到前5个数据
 *   5. 两个String类型集合字符串合并
 *   6. 转换成Person类型
 *   7. 展示数据
 *
 *   太浪费资源,浪费时间!!!
 * @author Anonymous 2020/3/12 15:22
 */
public class Demo8 {
    public static void main(String[] args) {
        //  1. 一个String类型的字符串集合,"1,骚磊,16"
        ArrayList<String> list1 = new ArrayList<>();

        list1.add("1,骚磊,15");
        list1.add("2,骚杰,65");
        list1.add("3,老黑,45");
        list1.add("4,老付,56");
        list1.add("5,污云,56");
        list1.add("6,帅栋,26");
        list1.add("7,帅栋,56");
        list1.add("8,帅栋,25");
        list1.add("9,帅栋,26");
        list1.add("10,帅栋,26");
        list1.add("11,帅栋,25");
        list1.add("12,帅栋,56");
        list1.add("13,帅栋,55");

        // 2. 过滤没有5的数据
        ArrayList<String> list2 = new ArrayList<>();
        for (String s : list1) {
            if (s.contains("5")) {
                list2.add(s);
            }
        }
        System.out.println(list2);

        // 3. 跳过前三个数据
        ArrayList<String> list3 = new ArrayList<>();
        for (int i = 3; i < list2.size(); i++) {
            list3.add(list2.get(i));
        }
        System.out.println(list3);

        // 4. 限制得到前5个数据
        ArrayList<String> list4 = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            list4.add(list3.get(i));
        }

        // 5. 两个String类型集合字符串合并
        ArrayList<String> list5 = new ArrayList<>();

        list5.add("1,骚磊,15");
        list5.add("2,骚杰,65");
        list5.add("3,老黑,45");
        list5.add("4,老付,56");
        list5.add("5,污云,56");

        list4.addAll(list5);

        // 6. 转换成Person类型
        ArrayList<Person> list6 = new ArrayList<>();
        for (String s : list4) {
            String[] split = s.split(",");
            Person person = new Person();

            person.setId(Integer.parseInt(split[0]));
            person.setName(split[1]);
            person.setAge(Integer.parseInt(split[2]));

            list6.add(person);
        }

        // 7. 展示数据
        for (Person person : list6) {
            System.out.println(person);
        }

    }
}
代码语言:javascript
复制
package com.qfedu.c_streamfunction;

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

/**
 * 采用原始的Stream流对象思想方式操作
 *   1. 一个String类型的字符串集合,"1,骚磊,16"
 *   2. 过滤没有5的数据
 *   3. 跳过前三个数据
 *   4. 限制得到前5个数据
 *   5. 两个String类型集合字符串合并
 *   6. 转换成Person类型
 *   7. 展示数据
 * @author Anonymous 2020/3/12 15:29
 */
public class Demo9 {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();

        list1.add("1,骚磊,15");
        list1.add("2,骚杰,65");
        list1.add("3,老黑,45");
        list1.add("4,老付,56");
        list1.add("5,污云,56");
        list1.add("6,帅栋,26");
        list1.add("7,帅栋,56");
        list1.add("8,帅栋,25");
        list1.add("9,帅栋,26");
        list1.add("10,帅栋,26");
        list1.add("11,帅栋,25");
        list1.add("12,帅栋,56");
        list1.add("13,帅栋,55");

        ArrayList<String> list2 = new ArrayList<>();

        list2.add("1,骚磊,15");
        list2.add("2,骚杰,65");
        list2.add("3,老黑,45");
        list2.add("4,老付,56");
        list2.add("5,污云,56");
        list2.add("6,帅栋,26");
        list2.add("7,帅栋,56");

        Stream<String> stream = list1.stream();

        Stream<String> limit = stream.filter(s -> s.contains("5")).
                skip(3).
                limit(5);

        Stream.concat(limit, list2.stream()).map(s -> {
            String[] split = s.split(",");
            Person person = new Person();

            person.setId(Integer.parseInt(split[0]));
            person.setName(split[1]);
            person.setAge(Integer.parseInt(split[2]));

            return person;
        }).forEach(System.out::println);

    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Stream
    • 1. Stream流
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档