Java中Stream流式编程从入门到精通

一.简介特性

1.Java8开始引入,支持链式书写;

2.存在惰性计算,短路操作,可消费性,所以性能上要优于传统编程;

        (1).惰性计算:流的元素只在需要时才进行计算,不会提前计算整个流;

        (2).短路操作:类似于 && ,|| 前面满足条件,后面的计算直接略过;

        (3).可消费性:流只能被消费一次,即每个元素只能被处理一次;

3.流在管道中流通,在节点被处理;

4.流【无存储】,流不是一种数据结构,流存储的只是一种数据视图;

5.对于无限序列,如果直接调用  forEach()  或者  count()  求最终值,会直接进入死循环,因为无限序列永远不可能被计算完。所以我们需要先将起转变为有序序列,例如 limit(100) ;

6.并行计算: Stream 为单线程,当我们要使用多线程时,直接使用 parallel() ,自动转化多线程。

二.使用

        1.常用操作关键字:

中间操作最终操作
map映射,转换forEach遍历
filter从头截取到指定索引位置collectcount:返回元素个数
skip从指定的索引后一位截取到最后

(聚合)

count:返回元素个数
sorted排序max:找出最大元素
distinct去重min:找出最小元素
concat合并流sum:求总和
flatMap平面化处理sverage:求平均
limit从头截取到指定索引位置

mapToInt

mapToDoube

mapToLong

转成整型流

转成小数流

转成长整型流

        2.创建使用:

                (1)of()创建:
        Stream<Integer> intStream = Stream.of(1, 2, 3, 4, 5);
        intStream.forEach(System.out::println);
                (2)使用集合:
 //1.创建list集合 转成流
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(i);
        }
        //转成流
        list.stream().forEach(System.out::println);
        
        //2.直接创建
        Stream<String> stream = Arrays.stream(new String[]{"1","2"});
                (3)采用 Stream.generate() ,传入Supplier对象。基于Supplier创建的Stream会不断调用 Supplier.get() 方法来生成下一个元素,这种Stream中保留的不是元素,而是算法
        //主函数
	Stream<Integer> my = Stream.generate(new MySup());
    my.limit(10).forEach(System.out::println);
		
		//MySup类:
 		// 不断生成自然数的Supplier(范围在Integer之内)
    static class MySup implements Supplier<Integer> {
        int n = 0;
        public Integer get() {
            n++;
            return n;
        }
    }

        3.常规操作:

                (1)三种基本类型流          

                 Java泛型不支持基本类型,所以我们无法使用像 Stream<int> 这样的形式来保存int,只能采用形如 Integer 这样的形式。但是频繁装箱、拆箱操作会牺牲编译器的大量性能。

​                 所以为了提高效率,Java标准库提供了三种使用基本类型的 Stream ,它们的使用和标准的Stream没有太大区别,直接使用: IntStream  , LongStream,   DoubleStream; 

// 1. 直接创建int流
IntStream is = Arrays.stream(new int[] { 1, 2, 3 });

// 2. 将Stream<String>转换为LongStream:
LongStream s=List.of("1").stream().mapToLong(Long::parseLong);
                (2)map() 映射操作

                它将一个 Stream 转换为另一个 Stream 

                    a.每一次映射都会自赋值,形如:a = a + 1 可写成 a+1,所以不再需要编写赋值语句
 //自赋值
 Stream<Integer> intStream = Stream.of(1, 2, 3, 4, 5);
 intStream.map(a -> a+1).forEach(System.out::print);//输出:23456
                    b.可以实现类型转换, map() 方法接收一个  Function 接口对象,负责做类型转换
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
List<String> strings = new ArrayList<>();
strings.add("  AbCde  ");
strings.add("  asd  ");
//去空格,转小写
strings.stream().map(String::trim).map(String::toLowerCase).forEach(System.out::print);//输出:abcdeasd
                (3)sorted() 排序操作
System.out.println("排序");
//1.默认从小到大
list.stream().sorted().forEach(System.out::print);
System.out.println("------");
//2.可自定义过滤器,传入a,b两个参数,b-a为从大到小
list.stream().sorted((a,b)-> b-a).forEach(System.out::print);
                (4)filter() 过滤操作
//list=[1,2,3,4,5,6,7,8,9],输出大于3的元素
list.stream().filter(a -> a > 3).forEach(System.out::println);//输出:456789
                (5)distinct()去重
Arrays.stream(new int[]{1, 1, 2, 3, 2, 2}).distinct().forEach(System.out::print);//输出:123
                (6)limit()截取前面
//从0号索引开始,截取4个
list.stream().limit(4).forEach(System.out::print);//输出:0123
                (7)skip() 截取后面
//从第5个开始,到最后
list.stream().skip(4).forEach(System.out::print);//输出:456789
                (8)concat() 合并流
System.out.println("合并流");
Stream<String> stream1 = Arrays.stream(new String[]{"qw", "we", "rt"});
Stream<String> stream2 = Arrays.stream(new String[]{"as", "sd", "df"});
Stream.concat(stream1,stream2).forEach(System.out::print);//输出:qwwertassddf
                (9)flatMap() 平面化处理,将三维数据转成二维数据(将二维数组转成一维数组)

undefined

        List<List<Integer>> listList = new ArrayList<>();
        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);
        ArrayList<Integer> list2 = new ArrayList<>();
        list2.add(9);
        list2.add(7);
        list2.add(8);
        listList.add(list1);
        listList.add(list2);
        listList.stream().forEach(System.out::print);//输出:[1, 2, 3][9, 7, 8]
        System.out.println();
        listList.stream().flatMap(ls -> ls.stream()).forEach(System.out::print);//输出:123978
                (10)forEach() 遍历
Stream<Integer> intStream = Stream.of(1, 2, 3, 4, 5);
intStream.forEach(System.out::println);
                (11)collect() 转化成集合
/**list=[0,1,2,3,4,5,6,7,8,9]*/
//1.操作完stream,转化成List
 listList<Integer> collect = list.stream().map(a -> a + 3).collect(Collectors.toList());
 System.out.println(collect); //输出:[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

//2.操作完stream,转化成Set
 Set<Integer> collectSet = list.stream().map(a -> a + 2).collect(Collectors.toSet());
 System.out.println(collectSet);//输出:[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

//3.操作我stream,转化成Map
//3-1.list中存放基本类型
 List<Character> strList = new ArrayList<>();
 strList.add('a');
 strList.add('b');
 strList.add('c');
 strList.add('e');
 strList.add('f');
//转map时,用strList的索引当作key,strList中的每一个元素当作value
 Map<Integer, Character> collectMap1 = strList.stream().collect(Collectors.toMap(obj->strList.indexOf(obj), obj->obj,(a,b)-> a));
 System.out.println(collectMap1);//输出:{0=a, 1=b, 2=c, 3=e, 4=f}

//3-2.list中存放对象
 List<Person> people = new ArrayList<>();
 people.add(new Person(1,"杨过"));
 people.add(new Person(2,"小龙女"));
 people.add(new Person(3,"周伯通"));
 people.add(new Person(4,"杨康"));
 people.add(new Person(5,"小龙男"));
//转map时,先把每个对象的编号+1然后当作key,用每个对象的name当作value
 Map<Integer, String> collectMap = people.stream().map(p ->{
       p.setNumber(p.getNumber()+1);
       return p;
 }).collect(Collectors.toMap(Person::getNumber, Person::getName,(a,b)-> a));
 System.out.println(collectMap);//输出:{2=杨过, 3=小龙女, 4=周伯通, 5=杨康, 6=小龙男}

//3-3. 把两个不同的集合转成map;
//使用strList中存放[a,b,c,e,f] 当作key,使用people中存放的[2=杨过, 3=小龙女, 4=周伯通, 5=杨康, 6=小龙男]的名称当作value
 Map<Character, String> collectMap2 = strList.stream().collect(Collectors.toMap(obj -> obj, p -> {
     Person person = people.get(strList.indexOf(p));
     return person.getName();
 },(key1,key2)->key1));
 System.out.println(collectMap2);//输出:{a=杨过, b=小龙女, c=周伯通, e=杨康, f=小龙男}


//3-4. List<Object> 转 Map<String, List<Object>> (分组)
//用名称分组
 Map<String, List<Person>> groupMap = people.stream().collect(Collectors.groupingBy(Person::getName));
 System.out.println(groupMap);//输出:{小龙男=[Person{number=6, name='小龙男'}], 杨过=[Person{number=2, name='杨过'}], 杨康=[Person{number=5, name='杨康'}], 周伯通=[Person{number=4, name='周伯通'}], 小龙女=[Person{number=3, name='小龙女'}]}
//以姓氏分组
 Map<String, List<Person>> groupMap1 = people.stream().collect(Collectors.groupingBy(p->p.getName().substring(0,1)));
 System.out.println(groupMap1);//输出:{周=[Person{number=4, name='周伯通'}], 杨=[Person{number=2, name='杨过'}, Person{number=5, name='杨康'}], 小=[Person{number=3, name='小龙女'}, Person{number=6, name='小龙男'}]}
                (12)数学(聚合)计算: max 最大, min 最小, count 个数, sum 总和, sverage 平均
  /**
         * list=[0,1,2,3,4,5,6,7,8,9]
         * perple=[Person{number=1, name='杨过'}, Person{number=2, name='小龙女'}, Person{number=3, name='周伯通'}, Person{number=4, name='杨康'}, Person{number=5, name='小龙男'}]
         */
        System.out.println("***max找最大***");
        //数字类型找最大 list=[0,1,2,3,4,5,6,7,8,9]
        Optional<Integer> maxInt = list.stream().max(Integer::compareTo);
        //通过get()方法获取最大值
        System.out.println(maxInt.get());//输出:9
        //字符串类型找最大
        Optional<String> maxString = Arrays.stream(new String[]{"a", "b", "c", "d", "b"}).max(String::compareTo);
        //通过get()方法获取最大值
        System.out.println(maxString.get());//输出d

        System.out.println("***min找最小***");
        Optional<Integer> min = list.stream().collect(Collectors.minBy(Integer::compareTo));
        System.out.println("min::"+min.get());//输出: minInt::0
        Optional<Person> min1 = people.stream().collect(Collectors.minBy(Comparator.comparing(Person::getNumber)));
        System.out.println("min1::"+min1.get()); //输出:minInt1::Person{number=1, name='杨过'}
        Optional<Person> min2 = people.stream().min(Comparator.comparing(Person::getNumber));
        System.out.println("min2::"+min2.get()); //输出:min2::Person{number=1, name='杨过'}

        System.out.println("***count个数***");
        long count = list.stream().count();
        System.out.println("count::"+count);


        System.out.println("***sum总和***");
        //原始写法
        Integer sum = list.stream().collect(Collectors.summingInt(s -> s));
        System.out.println("sum::"+sum);//输出:sum::45
        //使用mapToInt()转成IntStream,然后直接使用sum
        int sum1 = list.stream().mapToInt(Integer::intValue).sum();
        System.out.println("sum1::"+sum1);//输出:sum1::45
        //操作Person对象,获取编号,然后sum
        int sum2 = people.stream().mapToInt(Person::getNumber).sum();
        System.out.println("sum2::"+sum2);//输出:sum2::15


        System.out.println("***sverage平均***");
        //直接求平均
        Double avg = list.stream().collect(Collectors.averagingDouble(p -> p));
        System.out.println(avg);//输出:4.5
        //转成double,然后求平均
        OptionalDouble average = list.stream().mapToDouble(Integer::intValue).average();
        System.out.println(average.getAsDouble());//输出:4.5

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值