函数式编程 流Stream的使用
来源:互联网 发布:sql with as等价 编辑:程序博客网 时间:2024/05/16 11:36
内部迭代与外部迭代
使用for 循环计算来自伦敦的艺术家人数
- 外部迭代
int count = 0;for (Artist artist : allArtists) { if (artist.isFrom("London")) { count++; }}
使用Iterator迭代
int count = 0;Iterator<Artist> iterator = allArtists.iterator(); while(iterator.hasNext()) { Artist artist = iterator.next(); if (artist.isFrom("London")) { count++; } }
2.使用stream内部迭代
long count = allArtists.stream().filter(artist -> artist.isFrom("London")).count();
每种操作都对应Stream 接口的一个方法。为了找出来自伦敦的艺术家,需要对Stream 对象进行过滤:filter。过滤在这里是指“只保留通过某项测试的对象”。测试由一个函数完成,根据艺术家是否来自伦敦,该函数返回true 或者false。由于Stream API 的函数式编程风格,我们并没有改变集合的内容,而是描述出Stream 里的内容。count() 方法计算给定Stream 里包含多少个对象。
惰性求值和及早求值
只过滤,不计数
allArtists.stream().filter(artist -> artist.isFrom("London"));
这行代码并未做什么实际性的工作,filter 只刻画出了Stream,但没有产生新的集合。像filter 这样只描述Stream,最终不产生新集合的方法叫作惰性求值方法;而像count 这样最终会从Stream 产生值的方法叫作及早求值方法。
由于使用了惰性求值,没有输出艺术家的名字:
allArtists.stream().filter(artist -> { System.out.println(artist.getName()); return artist.isFrom("London");});
如果将同样的输出语句加入一个拥有终止操作的流,如例3-3 中的计数操作,艺术家的名字就会被输出
long count = allArtists.stream().filter(artist -> { System.out.println(artist.getName()); return artist.isFrom("London");}).count();
判断一个操作是惰性求值还是及早求值很简单:只需看它的返回值。
如果返回值是Stream,那么是惰性求值;
如果返回值是另一个值或为空,那么就是及早求值。
常用的流操作
collect(toList())
collect(toList()) 方法由Stream 里的值生成一个列表,是一个及早求值操作。
@Test public void testCollect() throws Exception { //Stream 的of 方法使用一组初始值生成新的Stream List<String> collected = Stream.of("a", "b", "c").collect(Collectors.toList()); Assert.assertEquals(Arrays.asList("a", "b", "c"), collected); }
map
如果有一个函数可以将一种类型的值转换成另外一种类型,map 操作就可以使用该函数,将一个流中的值转换成一个新的流。
@Test public void testMap() throws Exception { //小写转大写 List<String> upperWords = new ArrayList<>(); //for循环实现 for (String s : Arrays.asList("a", "b", "c")) { upperWords.add(s.toUpperCase()); } Assert.assertEquals(Arrays.asList("A", "B", "C"), upperWords); //lambda实现 upperWords = Stream.of("a", "b", "c") .map(string -> string.toUpperCase()) .collect(Collectors.toList()); Assert.assertEquals(Arrays.asList("A", "B", "C"), upperWords); }
filter
遍历数据并检查其中的元素时,可尝试使用Stream 中提供的新方法filter
@Test public void testFilter() throws Exception { //判断是否以数字开头 List<String> beginWithNumber = new ArrayList<>(); //for循环实现 for (String s : Arrays.asList("1aa", "2bb", "cccc")) { if (isDigit(s.charAt(0))) { beginWithNumber.add(s); } } Assert.assertEquals(Arrays.asList("1aa", "2bb"), beginWithNumber); //lambda实现 beginWithNumber = Stream.of("1aa", "2bb", "cccc") .filter(string -> isDigit(string.charAt(0))) .collect(Collectors.toList()); Assert.assertEquals(Arrays.asList("1aa", "2bb"), beginWithNumber); }
flatMap
flatMap 方法可用Stream 替换值, 然后将多个Stream 连接成一个Stream
@Test public void testFlatMap() throws Exception { List<Integer> collect = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6)) .flatMap(numbers -> numbers.stream()) .collect(Collectors.toList()); Assert.assertEquals(Arrays.asList(1, 2, 3, 4, 5, 6), collect); }
max和min
求最大值和最小值
@Test public void testMaxAndMin() throws Exception { List<Track> trackList = Arrays.asList(new Track("Bakai", 524), new Track("Violets for Your Furs", 378), new Track("Time Was", 451)); Track shotestTrack = trackList.stream() .min(Comparator.comparing(track -> track.getLength())) .get(); Track longestTrack = trackList.stream() .max(Comparator.comparing(track -> track.getLength())) .get(); Assert.assertEquals(trackList.get(1), shotestTrack); Assert.assertEquals(trackList.get(0), longestTrack); }
reduce
可以实现从一组值中生成一个值
@Test public void testReduce() throws Exception { int sum = Stream.of(1, 2, 3, 4) .reduce(0, (a, b) -> a + b);//0是初始值 Assert.assertEquals(10, sum); int multi = Stream.of(10, 20, 30) .reduce(1, (a, b) -> a * b); Assert.assertEquals(6000, multi); //将reduce 操作展开 BinaryOperator<Integer> accumulator = (acc, element) -> acc + element; int count = accumulator.apply( accumulator.apply( accumulator.apply(0, 1), 2), 3); }
高阶函数
高阶函数是指接受另外一个函数作为参数,或返回一个函数的函数。
高阶函数不难辨认:看函数签名就够了。
如果函数的参数列表里包含函数接口,或该函数返回一个函数接口,那么该函数就是高阶函数。
总结
内部迭代将更多控制权交给了集合类。
和 Iterator 类似,Stream 是一种内部迭代方式。
将 Lambda表达式和 Stream 上的方法结合起来,可以完成很多常见的集合操作。
- 函数式编程 流Stream的使用
- 函数式编程----stream.js
- Stream API函数式编程
- Java8函数式编程之六 :Stream (流)介绍
- Java8函数式编程之七:Stream(流)的各种操作
- 【转】JAVA8-Stream弥补函数式编程
- java函数式编程之Stream
- 16.3 Stream流式编程
- Java 8函数式编程笔记(二)- 集合和流(stream)
- java8新特性 lambda Stream map(函数式编程)
- Java1.8新特性 Lambda/Stream/函数式编程
- JAVA 函数式编程学习之Stream API
- java8新特性 lambda Stream map(函数式编程)
- java8新特性 lambda Stream map(函数式编程)
- C#流Stream的使用总结
- stream benchmark 的使用
- mjpg-stream的使用
- iPhone 网络编程:使用stream建立通讯
- Android Framework学习(七)之Thread类以及常用同步类
- Mybatis---配置文件添加提示
- spring In Action 笔记
- 二分贪心专题总结
- 线程安全与锁优化
- 函数式编程 流Stream的使用
- 数组
- 最长连续序列
- mapreduce 编程思想
- 你想要别人记住你什么?
- 数据结构-单链表
- Linux Ubuntu 16.04 初次安装使用总结zzz
- Searching for Patterns の Set 1 (Naive Pattern Searching)
- 项目中的web.xml基础理解