1, 认识stream(声明式编程)

Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator, 原始版本的Iterator,用户只能一个一个的遍历元素并对其执行某些操作;高级版本的Stream,用户只要给出需要对其包含的元素执行什么操作,比如“过滤掉长度大于10的字符串”、“获取每个字符串的首字母”等,具体这些操作如何应用到每个元素上,就给Stream就好了!

Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程

2, 使用stream的基本过程

1, 创建Stream;

2, 转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象(**可以有多次转换**);

3, 对Stream进行聚合(Reduce)操作,获取想要的结果;

3, 创建stream

1), 使用stream静态方法创建

@Test

public void test() {

// of

Stream integerStream = Stream.of(1, 2, 3, 5);

// generate, 无限长度, 懒加载, 类似工厂, 使用必须指定长度

Stream generate = Stream.generate(Math::random);

// iterator方法, 无限长度,

Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::print);

}

2), 通过collection的子类生成

Collection.stream()

Collection.parallelStream()

Arrays.stream(T array) or Stream.of()

@Testpublic voidtest2() {

List integers = Arrays.asList(1, 2, 3, 4, 5, 6);

Stream stream =integers.stream();

}

3), buffer生成 (通过实现 Supplier 接口)

java.io.BufferedReader.lines()

Pattern.splitAsStream(java.lang.CharSequence)

java.util.stream.IntStream.range()

4), 自定义supplier接口

@Testpublic voidtest13() {

Stream.generate(newPersonSupplier()).

limit(10).

forEach(p-> System.out.println(p.getName() + "," +p.getAge()));

}private class PersonSupplier implements Supplier{private int index = 0;private Random random = newRandom();

@Overridepublic Person get() {return new Person(index++, "StormTestUser" + index, random.nextInt(100));

}

}

流的主要操作( https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/index.html )

Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。

Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。

分类操作

Intermediate:

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

Terminal:

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

Short-circuiting:

anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit

4, 转换stream

每次使用的本质, 是创建了一个新的stream, 旧的stream保持不变

1. distinct: 对于Stream中包含的元素进行去重操作(去重逻辑依赖元素的equals方法),新生成的Stream中没有重复的元素;2. filter: 对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素;3. map: 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。

有 mapToInt, mapToLong, mapToDouble

直接转换为响应的类型, 避免拆装箱的消耗4. flatMap:和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中;5. peek: 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数;6. limit: 对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素;7. skip: 返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream;

8. range: 截取

9, sorted: 排序

排序使用:

@Testpublic voidtest11() {

List list = Arrays.asList("2", "5", "2", "1", "8", "4", "3", "7", "9");

List list2 = list.stream().distinct().sorted((o1, o2) -> (Integer.parseInt(o2) -Integer.valueOf(o1))).collect(Collectors.toList());

System.out.println(list2);

}

综合:

@Testpublic voidtest3() {

List integers = Arrays.asList(1, 1, 3 , null, 2, null, 3, 4, 5, 8, 10);

System.out.println(integers.stream().filter(num -> num != null)

.distinct()

.mapToInt(num-> num * 10)

.peek(System.out::println).skip(2).limit(4).sum());

}

关于多次stream的性能问题:

转换操作都是lazy的,多个转换操作只会在汇聚操作(见下节)的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在汇聚操作的时候循环Stream对应的集合,然后对每个元素执行所有的函数。

流转换其他数据结构

//1. Array

String[] strArray1 = stream.toArray(String[]::new);//2. Collection

List list1 =stream.collect(Collectors.toList());

List list2 = stream.collect(Collectors.toCollection(ArrayList::new));

Set set1=stream.collect(Collectors.toSet());

Stack stack1= stream.collect(Collectors.toCollection(Stack::new));//3. String

String str = stream.collect(Collectors.joining()).toString();

5, 汇聚操作

汇聚操作(也称为折叠)接受一个元素序列为输入,反复使用某个合并操作,把序列中的元素合并成一个汇总的结果。比如查找一个数字列表的总和或者最大值,或者把这些数字累积成一个List对象。Stream接口有一些通用的汇聚操作,比如reduce()和collect();也有一些特定用途的汇聚操作,比如sum(),max()和count()

1), 可变汇聚, collect, 把输入的元素们累积到一个可变的容器中,比如Collection或者StringBuilder;

R collect(Suppliersupplier,accumulator, combiner);

Supplier supplier是一个工厂函数,用来生成一个新的容器;

BiConsumer accumulator也是一个函数,用来把Stream中的元素添加到结果容器中;

BiConsumer combiner还是一个函数,用来把中间状态的多个结果容器合并成为一个(并发的时候会用到)

@Testpublic voidtest4() {

List nums = Arrays.asList(1, 1, 3 , null, 2, null, 3, 4, 5, 8, 10);

List numsWithCollect = nums.stream().filter(num -> num != null)

.collect(()-> new ArrayList(),

(list, item)->list.add(item),

(list1, list2)->list1.addAll(list2));

System.out.println(numsWithCollect);

}

太繁琐了, 在jdk8 中提供了Collectors工具类, 可以直接实现汇聚( http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html )

@Testpublic voidtest5() {

List nums = Arrays.asList(1, 1, 3 , null, 2, null, 3, 4, 5, 8, 10);

List collect = nums.stream().filter(num -> num != null)

.collect(Collectors.toList());

System.out.println(collect);

}

ps: collectos中提供了大量的方法, 粘贴一段api开头的方法

//Accumulate names into a List

List list =people.stream().map(Person::getName).collect(Collectors.toList());//Accumulate names into a TreeSet

Set set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));//Convert elements to strings and concatenate them, separated by commas

String joined =things.stream()

.map(Object::toString)

.collect(Collectors.joining(","));//Compute sum of salaries of employee

int total =employees.stream()

.collect(Collectors.summingInt(Employee::getSalary)));//Group employees by department

Map>byDept=employees.stream()

.collect(Collectors.groupingBy(Employee::getDepartment));//Compute sum of salaries by department

MaptotalByDept=employees.stream()

.collect(Collectors.groupingBy(Employee::getDepartment,

Collectors.summingInt(Employee::getSalary)));//Partition students into passing and failing

Map> passingFailing =students.stream()

.collect(Collectors.partitioningBy(s-> s.getGrade() >= PASS_THRESHOLD));

2) reduce汇聚

@Testpublic voidtest6() {

List nums = Arrays.asList(1, 1, 3 , null, 2, null, 3, 4, 5, 8, 10);

Integer count= nums.stream().filter(num -> num != null)

.reduce((sum, num)-> sum + num).get();

System.out.println(count);

}

可以看到reduce方法接受一个函数,这个函数有两个参数,第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数。要注意的是:**第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素**。这个方法返回值类型是Optional,这是Java8防止出现NPE的一种可行方法,后面的文章会详细介绍,这里就简单的认为是一个容器,其中可能会包含0个或者1个对象。

可以提供一个初始值, 如果ints为空则直接返回默认值

List ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);

System.out.println("ints sum is:" + ints.stream().reduce(0, (sum, item) -> sum + item));

count()

List ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);

System.out.println("ints sum is:" + ints.stream().count());

match()

@Testpublic voidtest7() {

List nums = Arrays.asList(1, 1, 3 , null, 2, null, 3, 4, 5, 8, 10);

System.out.println(nums.stream().filter(num -> num != null).allMatch(num -> num < 8));

}

max(), min()

@Testpublic voidtest12() throws IOException {

BufferedReader br= new BufferedReader(new FileReader("d:\\test.log"));int longest =br.lines().

mapToInt(String::length).

max().

getAsInt();

br.close();

System.out.println(longest);

}

– allMatch:是不是Stream中的所有元素都满足给定的匹配条件

– anyMatch:Stream中是否存在任何一个元素满足匹配条件

-  noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true

– findFirst: 返回Stream中的第一个元素,如果Stream为空,返回空Optional

– noneMatch:是不是Stream中的所有元素都不满足给定的匹配条件

– max和min:使用给定的比较器(Operator),返回Stream中的最大|

3) 分组

按年龄分组

@Testpublic voidtest13() {

Map> personGroups = Stream.generate(newPersonSupplier()).

limit(100).

collect(Collectors.groupingBy(Person::getAge));

Iterator it=personGroups.entrySet().iterator();while(it.hasNext()) {

Map.Entry> persons =(Map.Entry) it.next();

System.out.println("Age" + persons.getKey() + "=" +persons.getValue().size());

}

}

按是否成年分组

@Test

public void test13() {

Map> children = Stream.generate(new PersonSupplier()).

limit(100).

collect(Collectors.partitioningBy(p -> p.getAge() < 18));

System.out.println("Children number: " + children.get(true).size());

System.out.println("Adult number: " + children.get(false).size());

}

一个综合运用的例子:

MongoClient client =getMongoClient();

MongoDatabase mongoDatabase=client.getDatabase(Constance.database());

MongoCollection collection =mongoDatabase.getCollection(Constance.collection());

MongoIterable iter = collection.find().map(document ->{

String topic= document.get("topic").toString().toUpperCase();

String mac= document.get("mac").toString().toUpperCase();return newTopicMacEntity(topic, mac);

});

Map> collect =Lists.newArrayList(iter).stream().collect(Collectors.groupingBy(TopicMacEntity::topic));

Map> resultMap =collect.entrySet().stream()

.collect(Collectors.toMap(Map.Entry::getKey, v-> v.getValue().stream().map(t ->t.mac()).collect(Collectors.toList())));return resultMap;

更多grouping的强大用法:

http://developer.51cto.com/art/201404/435431.htm

原博客:

http://ifeve.com/stream/

lambda stream 循环_jdk8-lambda-stream的使用相关推荐

  1. 当你的Stream遇上Lambda就爱上了,超级无敌酷酷 - 第418篇

    历史文章(累计400+篇文章) <国内最全的Spring Boot系列之一> <国内最全的Spring Boot系列之二> <国内最全的Spring Boot系列之三&g ...

  2. Java8新特性概览——Stream特性,Lambda表达式,函数式接口Function、Predicate、Consumer,方法引用等概述

    概述: Java 8 新特性概述:https://www.ibm.com/developerworks/cn/java/j-lo-jdk8newfeature/index.html JAVA8 十大新 ...

  3. Stream流与Lambda表达式(一) 杂谈

    一.流 转换为数组.集合 package com.java.design.java8.Stream;import org.junit.Test; import org.junit.runner.Run ...

  4. 使用Java8新特性(stream流、Lambda表达式)实现多个List 的笛卡尔乘积 返回需要的List<JavaBean>

    需求分析: 有两个Long类型的集合 : List<Long> tagsIds; List<Long> attributesIds; 现在需要将这两个Long类型的集合进行组合 ...

  5. 【Java从入门到头秃专栏 7】语法篇(六) :Lambda表达式(->) 方法引用(::) stream流

    目录 1 Lambda表达式( -> ) ​ 2 方法引用( :: ) 3 Stream流 接下来介绍的三种语法叫:Lambda表达式 方法引用 stream流,这三种语法的使用要有特定条件,在 ...

  6. comparator接口_8000字长文让你彻底了解 Java 8 的 Lambda、函数式接口、Stream 用法和原理

    我是风筝,公众号「古时的风筝」.一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农! 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在 ...

  7. Lambda、函数式接口、Stream 一次性全给你

    就在今年 Java 25周岁了,可能比在座的各位中的一些少年年龄还大,但令人遗憾的是,竟然没有我大,不禁感叹,Java 还是太小了.(难道我会说是因为我老了?) 而就在上个月,Java 15 的试验版 ...

  8. 函数式编程(Lambda表达式、Optional、Stream流)

    函数式编程(Lambda表达式.Optional.Stream流) 文章目录 函数式编程(Lambda表达式.Optional.Stream流) 一.概述 1. 为什么要学习函数式编程? 2. 函数式 ...

  9. 10000字长文让你了解 Java 8 Lambda、函数式接口、Stream 用法和原理

    一定要看到最后,那是心动的感觉! 我是风筝,公众号「古时的风筝」.一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农!文章会收录在 JavaNewBee 中,更有 Java 后端知 ...

最新文章

  1. SpringMVC+MyBatis+Druid使用MySQL8.0.11版本
  2. Django startproject的问题
  3. 算法训练_ALGO14_回文数
  4. Visual C++——加速键
  5. 意大利归还中国文物;翟天临咪蒙成考公务员题目;携程回应五一机票涨价;腾讯未成年人网络保护体系上线;这就是今天的大新闻...
  6. 钉钉、腾讯朋友等被点名!微信公示部分违规行为:连自家人都没放过
  7. java健康检查的作用,spring cloud分布式健康检查
  8. 对yolo与fasterrcnn anchors的理解
  9. 互联网架构技术干货视频分享地址发布和情况说明
  10. 数据分析五板斧与里面的屠龙刀(下)
  11. 【进阶】python写一个小猫
  12. 羊皮卷之七:我要笑遍世界
  13. 托米的咒语 牛客练习赛23 D
  14. 史上最详细的AVL树(含代码实现)
  15. 鸿蒙四月几号升级啊,华为鸿蒙系统升级时间表 鸿蒙系统第二批升级时间是什么时候...
  16. 米氏散射多次散射计算程序
  17. 手机换IP的方法--手机PPTP
  18. 从C到B,20岁的腾讯正在经历一场“生死”腾挪
  19. 动态规划:求两个字符串的最长公共子序列
  20. 30个单片机常见问题及解决办法!

热门文章

  1. matlab改变示波器颜色,[转载]matlab/simulink 示波器颜色设置
  2. index.php文件分析,OpenCart index.php分析
  3. 安装go client调用Kubernetes API
  4. hdu 1078 FatMouse and Cheese(记忆化搜索)
  5. SpringMVC基础学习(二)—开发Handler
  6. [已修正]安装struts找不到tld文件
  7. 查询SQL的null与''
  8. VSTS 下的敏捷开发模板
  9. 6个最佳的开源Python应用服务器
  10. Glib2中G_DEFINE_TYPE原理(四)