Java 8 新特性 Stream 简介与常用方法

Java 8 新特性 Stream 简介与常用方法

Stream 是什么

Stream

在介绍 Stream 之前,先回顾一下以往的集合操作。比如对于一个 list,需要统计其中大于 3 的数字,可能会使用迭代器写出如下的代码遍历 list 进行统计。

List<Integer> list = Arrays.asList(1,2,3,4,5);
Iterator<Integer> iterator = list.iterator();
int countBigThan3 = 0;
while (iterator.hasNext()) {
    Integer value = (Integer) iterator.next();
	if(value > 3)
    countBigThan3 ++;
}

这种传统的迭代操作被称为外部迭代,

Java 8 为我们带来了 Stream。Stream 是用函数式编程方式在集合类上进行复杂操作的工具。上面的统计代码可以基于 Stream 改写成如下代码。可以看到,代码中几乎只有比较和统计操作,代码简单,逻辑清晰。其中,filter 方法传入了一个 lambda 表达式用于筛选大于 3 的数字,count 方法统计了筛选过数字的个数。

List<Integer> list = Arrays.asList(1,2,3,4,5);
long countBigThan3 = list.stream()
    .filter(value -> value > 3)
    .count();

Stream 的这种迭代操作被称为内部迭代。应用代码通过 Stream 构建迭代的逻辑,然后在集合代码中完成迭代,应用代码只需要迭代后获取结果即可。在上面的代码中,filter 方法描述了 Stream 的操作但并不立即执行,只有.count执行的时候filter方法才会执行,这样的方法被称为惰性求值方法.(而这得益于Lambda的延迟执行特性。)

获取流

获取一个流非常简单,有以下几种常用的方式:
1.所有的Collection 集合都可以通过stream 默认方法获取流;
2.Stream 接口的静态方法of 可以获取数组对应的流。
3.Map获取流:java.util.Map 接口不是Collection 的子接口,且其K-V数据结构不符合流元素的单一特征,所以获取对应的流需要分key、value或entry等情况:

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
public class Demo05GetStream {
public static void main(String[] args) {
	Map<String, String> map = new HashMap<>();
// ...
		Stream<String> keyStream = map.keySet().stream();
		Stream<String> valueStream = map.values().stream();
		Stream<Map.Entry<String, String>> entryStream = 				 map.entrySet().stream();
	 }
}

常用方法

1.延迟方法:返回值类型仍然是Stream 接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为延迟方法。)
2.终结方法:返回值类型不再是Stream 接口自身类型的方法,因此不再支持类似StringBuilder 那样的链式调用。本小节中,终结方法包括count 和forEach 方法。

forEach:虽然方法名字叫forEach ,但是与for循环中的“for-each”昵称不同。该方法接收一个Consumer 接口函数,会将每一个流元素交给该函数进行处理。

详见:笔记

void forEach(Consumer<? super T> action);
import java.util.stream.Stream;
public class Demo12StreamForEach {
	public static void main(String[] args) {
		Stream<String> stream = Stream.of("张无忌", "张三丰", "周芷若");
		stream.forEach(name‐> System.out.println(name));
	}
}

filter:

Stream<T> filter(Predicate<? super T> predicate);

该接口接收一个Predicate 函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件。

import java.util.stream.Stream;
public class Demo07StreamFilter {
	public static void main(String[] args) {
		Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
		Stream<String> result = original.filter(s ‐> s.startsWith("张"));
	}
}

映射:map

如果需要将流中的元素映射到另一个流中,可以使用map 方法

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

该接口需要一个Function 函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。

Stream流中的map 方法基本使用的代码如:

import java.util.stream.Stream;
public class Demo08StreamMap {
	public static void main(String[] args) {
		Stream<String> original = Stream.of("10", "12", "18");
		Stream<Integer> result = original.map(str‐>Integer.parseInt(str));
	}
}

统计个数:count

正如旧集合Collection 当中的size 方法一样,流提供count 方法来数一数其中的元素个数:

long count();

该方法返回一个long值代表元素个数(不再像旧集合那样是int值)。基本使用:

import java.util.stream.Stream;
public class Demo09StreamCount {
	public static void main(String[] args) {
	Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
	Stream<String> result = original.filter(s ‐> s.startsWith("张"));
	System.out.println(result.count()); // 2
	}
}

取用前几个:limit
limit方法可以对流进行截取,只取用前n个。方法签名:

Stream<T> limit(long maxSize);

参数是一个long型,如果集合当前长度大于参数则进行截取;否则不进行操作。基本使用:

	public class Demo10StreamLimit {
		public static void main(String[] args) {
			Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
			Stream<String> result = original.limit(2);
			System.out.println(result.count()); // 2
		}
	}

跳过前几个:skip

Stream<T> skip(long n);

如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流。基本使用:

public class Demo11StreamSkip {
	public static void main(String[] args) {
		Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
		Stream<String> result = original.skip(2);
		System.out.println(result.count()); // 1
	}
}

组合:concat

如果有两个流,希望合并成为一个流,那么可以使用Stream 接口的静态方法concat :

static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
备注:这是一个静态方法,与java.lang.String 当中的concat 方法是不同的。
public class Demo12StreamConcat {
	public static void main(String[] args) {
		Stream<String> streamA = Stream.of("张无忌");
		Stream<String> streamB = Stream.of("张翠山");
		Stream<String> result = Stream.concat(streamA, streamB);
	}
}

参考内容传送门:https://zhuanlan.zhihu.com/p/28226687

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值