---恢复内容开始---
了解了下关于stream的内容,把自己的理解和笔记还有一些自己写的demo放在下面
http://www.runoob.com/java/java8-streams.html
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
+--------------------+ +------+ +------+ +---+ +-------+ | stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect| +--------------------+ +------+ +------+ +---+ +-------+ 转换成代码: List<Integer> transactionsIds = widgets.stream() .filter(b -> b.getColor() == RED) .sorted((x,y) -> x.getWeight() - y.getWeight()) .mapToInt(Widget::getWeight) .sum();
流的操作类型分为两种:
Intermediate:
一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,
交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
Terminal:
一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。
Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。在对于一个 Stream 进行多次转换操作 (Intermediate 操作),
每次都对 Stream 的每个元素进行转换,而且是执行多次,这样时间复杂度就是 N(转换次数)个 for 循环里把所有操作都做掉的总和吗?其实不是这样的,
转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream 里有个操作函数的集合,
每次转换操作就是把转换函数放入这个集合中,在 Terminal 操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。
接下来,当把一个数据结构包装成 Stream 后,就要开始对里面的元素进行各类操作了。常见的操作可以归类如下。
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
特性:
1.不是数据结构
2.它没有内部存储,它只是用操作管道从 source(数据结构、数组、generator function、IO channel)抓取数据。
3.它也绝不修改自己所封装的底层数据结构的数据。例如 Stream 的 filter 操作会产生一个不包含被过滤元素的新 Stream,而不是从 source 删除那些元素。
4.所有 Stream 的操作必须以 lambda 表达式为参数
5.不支持索引访问
6你可以请求第一个元素,但无法请求第二个,第三个,或最后一个。不过请参阅下一项。
7.很容易生成数组或者 List
8.惰性化
9.很多 Stream 操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始。
10.Intermediate 操作永远是惰性化的。
11.并行能力
12.当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的。
13.可以是无限的
14.集合有固定大小,Stream 则不必。limit(n) 和 findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成。
以上都是些理论知识,下面附上自己写的几个demo
package com.lk.menu.stream; import java.io.*; import java.util.*; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; /** * @Author: Lukizzz * @Date: 2018/8/17 10:37 * @Description: 流的操作 */ public class StreamServiceTest { public static void main(String[] args) throws IOException { //1.流的map操作,大小写转换 List<String> wordList = new ArrayList<>(); wordList.add("apple"); wordList.add("pear"); List<String> output = wordList.stream().map(String::toUpperCase).collect(Collectors.toList()); //.collect(Collectors.toCollection(LinkedList::new System.out.println(output); //2.流的map操作,平方数 List<Integer> nums = Arrays.asList(1,2,3,4); List<Integer> aquareNums = nums.stream().map(n -> n * n).collect(Collectors.toList()); System.out.println(aquareNums); //3.IntStream构造流 IntStream.of(5,6,7,8).map(n -> n * n).forEach(System.out::println); //4.流的flatMap操作,把多个list的元素放在一个新的stream里 Stream<List<Integer>> inputStream = Stream.of( Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6) ); Stream<Integer> outputStream = inputStream.flatMap((childList) -> childList.stream()); //以数组的形式输出 outputStream.forEach(System.out::println); //以列表方式输出 //System.out.println( outputStream.collect(Collectors.toList())); //5.流的filter操作,先进行平方数再留下偶数(筛选) List<Integer> nums1 = Arrays.asList(1,2,3,4); List<Integer> aquareNums1 = nums1.stream().map(n -> n * n).filter( n -> n%2==0).collect(Collectors.toList()); System.out.println(aquareNums1); //6.peek不同于forEach直接结束,他可以多次使用,因为它对每个元素操作并返回一个新的stream //因为惰性的关系,所有操作是在最后一步一起执行的 Stream.of("one","two","three","four").filter(e -> e.length()>3).peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .collect(Collectors.toList()); //7.进行Short-circuiting的操作如findFirst、 findAny时返回的类型需要放在optional容器中 //多条件筛选是可行的 List<Integer> nums2 = Arrays.asList(1,2,3,4); Optional<Integer> aquareNums2 = nums2.stream().map(n -> n * n).filter(n -> n%2==0 && n>5 ).findFirst(); System.out.println(aquareNums2); //8.reduce()方法的几个demo //字符串拼接 String concat = Stream.of("A","B","C","D").reduce("",String::concat); System.out.println(concat); //求最小值 double minValue = Stream.of(-5.0,-2.0,3.0,5.0,10.0).reduce(Double.MAX_VALUE,Double::min); System.out.println(minValue); //求最大值 double maxValue = Stream.of(-5.0,-2.0,3.0,5.0,10.0).reduce(Double.MIN_VALUE,Double::max); System.out.println(maxValue); //求和,有初始值(初始值:算上这个值) int sumValue = Stream.of(5,6,7,8,9).reduce(0,Integer::sum); System.out.println(sumValue); //求和,无初始值,返回的是optional Optional<Integer> sumValue1 = Stream.of(5,6,7,8,9).reduce(Integer::sum); System.out.println(sumValue1); //过滤掉大写字母+字符串连接 concat = Stream.of("a", "B", "c", "D", "e", "F"). filter(x -> x.compareTo("Z") > 0). reduce("", String::concat); System.out.println(concat); /*9.文件中最长的一行的长度 distinct():去重复 sorted():排序 根据属性排序 Stream<T> sorted(Comparator<? super T> comparator); 对对象的进行操作Stream<T> peek(Consumer<? super T> action); 截断--取先maxSize个对象 Stream<T> limit(long maxSize); 截断--忽略前N个对象 Stream<T> skip(long n); */ BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\xxxx.txt"),"gb2312")); int longest = br.lines().mapToInt(String::length).max().getAsInt();br.close(); System.out.println(longest); //10.文件中最长的一行的单词(注意io流读取文件的时候要规定编码格式,不然会乱码) BufferedReader br1 = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\xxxx.txt"),"gb2312")); List<String> words = br1.lines().flatMap(line -> Stream.of(line.split(""))).filter(word -> word.length() > 0). map(String::toLowerCase).distinct().sorted().collect(Collectors.toList());br1.close(); System.out.println(words); /* allMatch:Stream 中全部元素符合传入的 predicate,返回 true anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true*/ //11.随机生成10个整数,筛选出其中的正整数 Random rand = new Random(); Supplier<Integer> supplier = rand::nextInt; Stream.generate(supplier).limit(10).filter(n ->n>0).forEach(System.out::println); //12.随机生成10个(10-100)之间的整数 Random random = new Random(); IntStream intStream = random.ints(10,100); intStream.limit(10).forEach(System.out::println); } }
运行结果截图:
在项目开发过程中又遇到了和stream相关的示例:
//按照uid分组并计算获得星星数的平均值
Map<Integer,Double> map = dataSearch.stream().collect(Collectors.groupingBy(AppraiseRecord::getAnchorUid,Collectors.averagingDouble(AppraiseRecord::getStarNum))); Map<Integer,Object> finalMap = new LinkedHashMap<>(); //将map按value值倒序排序并将结果add给finalMap map.entrySet().stream() .sorted(Map.Entry.<Integer,Double>comparingByValue() .reversed()).forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
//遍历finalMap并将数据添加进dataList for (Map.Entry<Integer,Object> entry:finalMap.entrySet()){ Map<Integer,Object> data = new HashMap<Integer, Object>(); data.put(1,entry.getKey()); BigDecimal bg = new BigDecimal((Double) entry.getValue()); double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); data.put(2,f1); dataList.add(data); }
原文:https://www.cnblogs.com/Lukizzz/p/9520210.html