文档章节

JDK8 Stream 从入门到装逼(三)

kaishui
 kaishui
发布于 2016/09/06 22:47
字数 1738
阅读 2.6K
收藏 116

lambdas中,可以看到lambda表达式让代码更加简洁、干净、容易理解,并允许不需要创建一个类就可以达到目的。lambdas很好的帮助开发人员更好的表达片段代码的意思,Stream对于集合提供一个抽象计算和Fluent接口更能让程序猿变得爽歪歪。

###1. 构建stream 初始化stream的几个方法

//1. Stream generate 生成无限个无序的stream
    Stream<String> stream = Stream.generate(() -> UUID.randomUUID().toString());
// 2. of 构造stream
    Stream<Integer> integerStream = Stream.of(1, 2, 4, 6, 3, 9, 7); 	      
//3.集合构造出stream
	Stream<List<Integer>> inputStream = Stream.of(
		    Arrays.asList(1),
		    Arrays.asList(2, 3),
		    Arrays.asList(4, 5, 6)
	);

###2. 可以怎样用stream


/**
 * jdk8 stream 用法
 * Created by kaishui on 2016/9/3.
 */
public class JDK_07StreamTest {
    static class User {
        private String name;
        private String password;

        public User(String name, String password) {
            this.name = name;
            this.password = password;
        }

        //省略getter and setter
    }


    public static void main(String[] args) {
        List<User> userList = new ArrayList<User>();
        userList.add(new User("name1", "passowrd1"));
        userList.add(new User("name4321", "passowrd4"));
        userList.add(new User("name321", "passowrd3"));
        userList.add(new User("kaishui", "kaishuiPassword"));
        userList.add(new User("name21", "passowrd2"));

        //1. 在jdk7之前的代码中,也许我们经常会这样写
        List<User> otherUsers = new ArrayList<>();
        for (User u : userList) {
            //获取含有 "name"的User
            if (null != u.getName() && u.getName().indexOf("name") >= 0) {
                otherUsers.add(u);
            }
        }
        //按照名字长度排序
        Collections.sort(otherUsers, new Comparator<User>() {
            @Override
            public int compare(User u1, User u2) {
                return u1.getName().length() - u2.getName().length();
            }
        });
        //打印
        for (User u : otherUsers) {
            System.out.println(u.getName());
        }
        System.out.println("-------我是一条分割线1---------");
        System.out.println("-------jdk8 示例---------");
        // 2. jdk8 使用stream操作集合
        List<String> nameList = userList.stream()
                .filter(u -> null != u.getName() && u.getName().indexOf("name") >= 0)	//过滤结果
                .sorted((u1, u2) -> u1.getName().length() - u2.getName().length())		//排序
                .map(u -> u.getName())													//提取
                .collect(Collectors.toList());											//把上述步骤后的结果转换成list
        //打印
        nameList.forEach(System.out::println);
    }
}

执行结果:

name1
name21
name321
name4321
-------我是一条分割线1---------
-------jdk8---------
name1
name21
name321
name4321

上面的例子,大概了解stream的用法,下面分点介绍一下: JDK8 collection中已经实现了一个default的stream方法

1. stream() 在集合collection中新建一个stream的管道,有点类似Linux命令中 grep or awk的用法。
2. filter(Predicate) 过滤条件, 看到Predicate应该可以想到就是过滤数据。
3. sorted(Comparator) 根据Comparator排序,英语国家的就是爽,写接口都可以省注释了.
4. map(Function) 提取计算,根据Funtion的作用,我们也知道,<T,R>输入一个T,返回一个R。
5. collect(Collectors.toList()) 把上述操作stream的结果转为另外一个集合。

如果不了解predicate、function的用法,可以系列篇之函数式接口编程

###3. stream 懒加载

// 1. of 构造 Stream<Integer>
Stream<Integer> integerStream = Stream.of(1, 2, 4, 6, 3, 9, 7).map(x -> x / 0);
System.out.println("-------我是一条分割线--------");

执行结果:

-------我是一条分割线--------

上述看到,map(x -> x/0)并没有执行,如果换成下面代码:

// 1. of 构造 Stream<Integer>
Stream<Integer> integerStream = Stream.of(1, 2, 4, 6, 3, 9, 7).map(x -> x / 0);
List<Integer> list = integerStream.collect(Collectors.toList());
System.out.println("-------我是一条分割线--------");

执行结果:

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at com.iu.jdk8.JDK_09StreamLazyLoadTest.lambda$main$0(JDK_09StreamLazyLoadTest.java:19)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
	at com.iu.jdk8.JDK_09StreamLazyLoadTest.main(JDK_09StreamLazyLoadTest.java:20)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

stream只有真正使用到的时候才去真正的执行。

###4. stream 链式编程什么时候才是结束

forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

当steam遇上这些方法才算是结束,其他的方法,例如:

map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

还是可以在上一个操作结果上继续操作,例如:根据条件filter -> sort -> map

 List<User> userList = new ArrayList<User>();
        for (int i = 0; i < 10; i++) {
            userList.add(new User("name" + i, "passowrd" + i, i));
        }
 List<String> nameList = userList.stream()
                .filter(u -> null != u.getName() && u.getName().indexOf("name") >= 0)	//过滤结果
                .sorted((u1, u2) -> u1.getName().length() - u2.getName().length())		//排序
                .map(u -> u.getName())													//提取
                .collect(Collectors.toList());											//把上述步骤后的结果转换成list

###5. stream api 例子

####5.1 distinct 去重

Stream.of(1, 2, 4, 6, 3, 9, 7, 2, 4, 9, 7).distinct().sorted().forEach(System.out::print);

//执行结果: 1234679

####5.2 skip 跳过条数 limit 限定结果返回几条

 Stream.of(1, 2, 4, 6, 3, 9, 7, 2, 4, 9, 7).skip(2).limit(3).forEach(System.out::print);
 //执行结果:463

####5.3 fitler 参数为:Predicate 过滤满足条件的结果, Count 统计条数

//获取集合中7的个数
long sum = Stream.of(1, 2, 4, 6, 3, 9, 7, 2, 4, 9, 7).filter(x -> x == 7).count();
System.out.println("sum = " + sum);

 //执行结果: sum = 2

####5.4 flatMap 使数据扁平化处理 很多情景,我们都会用到一个类中有List<Object>属性,怎样转化成Strean<Object>呢,这是flatMap就该出手了


public class JDK_08StreamFlatMapTest {
    static class User {
        private String name;
        private String password;
        private int no;

        public User(String name, String password, int no) {
            this.name = name;
            this.password = password;
            this.no = no;
        }

        //省略getter and setter
        
    }

    //班级
    static class Clazz{
        List<User> users;
        //省略getter and setter
    }


    public static void main(String[] args) {
        List<User> girlList = new ArrayList<User>();
        List<User> boyList = new ArrayList<User>();
        for (int i = 0; i < 10; i++) {
            girlList.add(new User("girl" + i, "passowrd" + i, i));
            boyList.add(new User("boy" + i, "passowrd" + i, i));
        }

        //班级1
        Clazz clazz = new Clazz();
        //班级2
        Clazz clazz2 = new Clazz();
        girlList.addAll(boyList);
        clazz.setUsers(girlList);
        clazz2.setUsers(girlList);
        //clazz stream
        Stream<Clazz> clazzSteam = Stream.of(clazz, clazz2);

        //clazz stream -> user stream 扁平化
        Stream<User> allUserStream = clazzSteam.flatMap(c -> c.getUsers().stream());
        System.out.println("两个班级一共多少人:" + allUserStream.count());;
    }
}

//执行结果:

两个班级一共多少人:40

####5.5 anyMatch

 //是否存在x*x = 81的结果
boolean flag = Stream.of(1, 2, 4, 6, 3, 9, 7, 2, 4, 9, 7).map(x -> x * x).anyMatch(x -> x == 81);
System.out.println(flag);
//执行结果:true

####5.6 reduce Optional<T> reduce(BinaryOperator<T> accumulator) 这个方法的主要作用是把 Stream 元素组合起来,Optional使用方法,请参考网红篇:Java函数式开发——优雅的Optional空指针处理

//clazz stream -> user stream
Stream<User> allUserStream = clazzSteam.flatMap(c -> c.getUsers().stream());
//串起所有名字 想了解optional用法可以参考:http://my.oschina.net/chkui/blog/739034
Optional<String> names = allUserStream.
        map(User::getName).sorted((first, second) -> first.compareTo(second))
        .reduce((first, second) -> first + " *** " + second);
System.out.println(names.get());

执行结果:

boy0 *** boy0 *** boy1 *** boy1 *** boy2 *** boy2 *** boy3 *** boy3 *** boy4 *** boy4 *** boy5 *** boy5 *** boy6 *** boy6 *** boy7 *** boy7 *** boy8 *** boy8 *** boy9 *** boy9 *** girl0 *** girl0 *** girl1 *** girl1 *** girl2 *** girl2 *** girl3 *** girl3 *** girl4 *** girl4 *** girl5 *** girl5 *** girl6 *** girl6 *** girl7 *** girl7 *** girl8 *** girl8 *** girl9 *** girl9

####5.7 Parallel 并行运行 vs 普通stream操作

long startTime = System.nanoTime();

Map<String, List<Integer>> numbersPerThread = IntStream.rangeClosed(1, 100000)
        .parallel()
        .boxed()
        .collect(Collectors.groupingBy(i -> Thread.currentThread().getName()));
long runTime = System.nanoTime() - startTime;
System.out.println("运行时间:" + String.valueOf(runTime));
//运行时间:159695489
long startTime = System.nanoTime();

Map<String, List<Integer>> numbersPerThread = IntStream.rangeClosed(1, 100000)
        .boxed()
        .collect(Collectors.groupingBy(i -> Thread.currentThread().getName()));
long runTime = System.nanoTime() - startTime;
System.out.println("运行时间:" + String.valueOf(runTime));
//运行时间:94576511

© 著作权归作者所有

kaishui
粉丝 54
博文 13
码字总数 11829
作品 0
广州
程序员
私信 提问
加载中

评论(11)

kaishui
kaishui 博主

引用来自“kaishui”的评论

引用来自“ODMark”的评论

怎么并行所花的时间还要长?是不是写反了?

不同数量等级 有不同时间和数学上y = ax + b , y = ax*x + b一样,在不同临界值以下,各有优势,但这里有可能真的写反了,谢谢指正

引用来自“ODMark”的评论

我是看到5.7里的两段代码除了parallel()之外是一模一样的,在没有特别说明使用场景和服务器情况下,一般并行运算的速度会比普通stream的快,当然,坑也多。😂
嗯,文章写到末尾人都变懒了,下次会注意的,没说明系统配置,确实会有不同
ODMark
ODMark

引用来自“kaishui”的评论

引用来自“ODMark”的评论

怎么并行所花的时间还要长?是不是写反了?

不同数量等级 有不同时间和数学上y = ax + b , y = ax*x + b一样,在不同临界值以下,各有优势,但这里有可能真的写反了,谢谢指正
我是看到5.7里的两段代码除了parallel()之外是一模一样的,在没有特别说明使用场景和服务器情况下,一般并行运算的速度会比普通stream的快,当然,坑也多。😂
kaishui
kaishui 博主

引用来自“ODMark”的评论

怎么并行所花的时间还要长?是不是写反了?

不同数量等级 有不同时间和数学上y = ax + b , y = ax*x + b一样,在不同临界值以下,各有优势,但这里有可能真的写反了,谢谢指正
ODMark
ODMark
怎么并行所花的时间还要长?是不是写反了?
z
zengworld
赞一个,写得非常好,可以安装这个来学习了。
随风溜达的向日葵
随风溜达的向日葵
很好很强大,手工点赞,逼格是满满的。
kaishui
kaishui 博主

引用来自“sameLuo”的评论

怎感觉像scala了
基于jvm平台运行的语言,满足JSR都相互学习
南湖王十三
南湖王十三
高大上啊
不安分的猿人
不安分的猿人
可以回去练习
sameLuo
sameLuo
怎感觉像scala了
玩转iOS开发:装逼技术RunTime的总结篇

文章分享至我的个人技术博客: cainrun.github.io/15077238804… 讲到这里, 的知识点和应用基本上就已经讲完了, 剩下的就靠大家自己在项目中的应用以及累积了. 这一篇文章主要是 转载声明:如需...

CainLuo
2017/10/24
0
0
很小心的发十条有趣的信息

一. 学习领域驱动设计 --- 连原作者都搞不清楚, 你去掺和什么? 二. 编写单元测试 --- 码字不够苦逼, 还要自残? 三. 学习UML设计 --- 没有这些东西, 世界更清净. 四. 学某门语言比某门语言挣钱...

大东哥
2012/04/26
1.3K
25
一个屌丝程序猿的人生(六十三)

  时间在奔跑。   转眼间,两个多月过去了。   “嘿!林萧,先别走啊。你的项目做的怎么样了?”   “是啊,林萧。先别急着走,把你的项目给我们看看呗。”   “张建说他已经做完了...

zuoxiaolong8810
2017/04/16
0
0
1小时入门Python

本套教程含有大量吹Nb成分!不乐意看请关闭 免责声明完事儿,老夫开始装B了 开始的寒暄,授人以渔,教程就是这个作用,首先明白几个道理: 1、入门!=精通 You can do sth,but no't do eve...

xh21bao
2017/04/09
0
0
数学老师装逼技巧,你绝对不会!

依稀记得,在小学到高中的学习生涯中,印象最深刻的就是数学老师了,总是觉得数学老师是最牛掰的,什么难题都能解,什么图都会画,好像就没有什么是能难倒他的。那么作为一名数学老师,你怎样...

学术研究软件
2016/04/25
463
0

没有更多内容

加载失败,请刷新页面

加载更多

广州哪里可以开汽车配件发票-中国-新闻网

广州哪里可以开汽车配件发票【152 * 9б 28 * 21 б9】陈生,诚、信、合、作,保、真、售、后、保、障、长、期、有、效。adb的全称为Android Debug Bri...

17095420210
8分钟前
25
0
Jprofile解析dump文件使用详解

1 Jprofile简介 官网 下载对应的系统版本即可 性能查看工具JProfiler,可用于查看java执行效率,查看线程状态,查看内存占用与内存对象,还可以分析dump日志. 2 功能简介 选择attach to a l...

JavaEd
10分钟前
15
0
广州哪里可以开服装费发票-中国-新闻网

广州哪里可以开服装费发票【152 * 9б 28 * 21 б9】陈生,诚、信、合、作,保、真、售、后、保、障、长、期、有、效。adb的全称为Android Debug Bridg...

17060824738
13分钟前
21
0
广州哪里可以开家用电器发票-中国-新闻网

广州哪里可以开家用电器发票【152 * 9б 28 * 21 б9】陈生,诚、信、合、作,保、真、售、后、保、障、长、期、有、效。adb的全称为Android Debug Bri...

17095186960
15分钟前
27
0
区块链毕业论文集【13】

区块链作为一种崭新的、颠覆性的技术,是国内外活跃的研究领域和毕业设计选题方向。本文列出最新的一组区块链方面的论文,希望可以对选择区块链毕业设计的同学们有所帮助,这是汇智网编辑整理...

区块链教程
33分钟前
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部