在Java 8 版本中新增的Stream,配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。
那么什么是Stream?
Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。
Stream可以由数组或集合创建,对流的操作分为两种:
1、中间操作,每次返回一个新的流,可以有多个。
2、终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。
另外,Stream有几个特性:
1、stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
2、stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
3、stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
我自己总结就是可以间接的把Stream看做是MySQL的一些命令方法的 流化 的操作版。当使用熟练Stream之后会发现结合MySQL用起来真的超级爽。
Stream可以通过集合数组创建。
1、通过 java.util.Collection.stream() 方法用集合创建流
List<Integer> list = Arrays.asList(1, 2, 3);
// 创建一个顺序流
Stream<Integer> stream = list.stream();
// 创建一个并行流
Stream<Integer> parallelStream = list.parallelStream();
2、使用java.util.Arrays.stream(T[] array)方法用数组创建流
int[] array={1,3,5,6,8};
IntStream stream = Arrays.stream(array);
3、使用Stream的静态方法:of()、iterate()、generate()(我不是很常用)
Stream<Integer> stream = Stream.of(1, 2, 3);
// of内部的方法,等同于使用数组创建流
@SafeVarargs
@SuppressWarnings("varargs") // Creating a stream from an array is safe
public static<T> Stream<T> of(T... values) {
return Arrays.stream(values);
}
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::print);
System.out.println();
Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);
输出结果:
0369
0.4918954920054893
0.8246638264369555
0.17880449237798712
创建一个案例类,之后的例子全部使用该类:
@Data
static class Dog {
private String name;
private int age;
private String sex;
public Dog() {
}
// 构造方法
public Dog(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String toString() {
return "name: " + name + "age: " + age + "sex: " + sex;
}
}
利用上面的Dog类,创建一个集合,下面操作将使用该集合:
List<Dog> list = new ArrayList<>();
list.add(new Dog("zhangsan", 2, "male"));
list.add(new Dog("lisi", 1, "male"));
list.add(new Dog("zhanglong", 3, "female"));
list.add(new Dog("zhaowu", 6, "female"));
list.add(new Dog("wangda", 5, "male"));
list.add(new Dog("alisa", 8, "female"));
Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的。Stream的遍历、匹配非常简单。(Optional类是一个可以为null的容器对象。使用isPresent()方法,如果有值会返回true,调用get()方法会返回该对象。更详细说明请见:菜鸟教程Java 8 Optional类)
public static void Test(String[] args){
/* 使用上述集合 */
// 遍历输出符合条件的元素
list.stream().forEach(System.out::println);
// 匹配第一个
Optional<Dog> findFirst = list.stream().findFirst();
// 匹配任意
Optional<Dog> findAny = list.stream().findAny();
// 是否包含符合特定条件的元素
boolean anyMatch = list.stream().anyMatch(e -> e.getAge() == 2);
System.out.println("匹配第一只狗:" + findFirst.get());
System.out.println("匹配任意一个狗:" + findAny.get());
System.out.println("是否存在年龄等于2的狗:" + anyMatch);
}
结果:
name: zhangsan age: 2 sex: male
name: lisi age: 1 sex: male
name: zhanglong age: 3 sex: female
name: zhaowu age: 6 sex: female
name: wangda age: 5 sex: male
name: alisa age: 8 sex: female
匹配第一只狗:name: zhangsan age: 2 sex: male
匹配任意一个狗:name: zhangsan age: 2 sex: male
是否存在年龄等于2的狗:true
注意:
使用findFirst()进行取第一个对象时在使用get()得到该对象时,有可能存在对象时null的情况,所以该处最好使用isPresent()进行一下非null校验。
筛选,就是按照一定的规则检查流中的元素,将符合条件规则的数据提取到新的流中
1、从Integer值的集合中筛选出大于8的值
public static void Test(String[] args){
List<Integer> testList = Arrays.asList(1,4,2,6,4,9,3);
testList.stream().filter(e -> e > 8).forEach(System.out::println);
}
结果:
9
2、将年龄大于7岁的Dog筛选出来
public static void Test(String[] args){
/* 使用上述集合 */
list.stream().filter(e -> e.getAge() > 7).forEach(System.out::println);
}
结果:
name: alisa age: 8 sex: female
映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:
1、输出所有狗的名字
/* 上述集合 */
list.stream().map(Dog::getName).forEach(System.out::println);
结果:
zhangsan
lisi
zhanglong
zhaowu
wangda
alisa
2、将所有狗的年龄加2
public static void Test(String[] args){
/* 使用上述集合 */
list.stream().map(e -> {
e.setAge(e.getAge() + 2);
return e.getAge();
}).forEach(System.out::println);
/* 等同于 */
list.stream().map(e -> e.getAge() + 2).forEach(System.out::println);
}
结果:
4
3
5
8
7
10
4
3
5
8
7
10
3、将两个字符集合组合并成一个新的字符集合。其中使用的collect(Collectors.toList())在后面会说。
public static void Test(String[] args){
/* 使用上述集合 */
List<String> list = Arrays.asList("a-b-c-d", "1-2-3-4");
List<String> newList = list.stream().flatMap(e -> {
// 将原集合中的单个元素拆分成一个数组
String[] split = e.split("-");
// 将数组中的元素转换成一个stream
Stream<String> e2 = Arrays.stream(split);
return e2;
}).collect(Collectors.toList());
System.out.println("处理前的集合:" + list);
System.out.println("处理后的集合:" + newList);
}
结果:
处理前的集合:[a-b-c-d, 1-2-3-4]
处理后的集合:[a, b, c, d, 1, 2, 3, 4]
max、min、count这些字眼你一定不陌生,在mysql中我们常用它们进行数据统计。Java Stream中也引入了这些概念和用法,方便了我们对集合、数组的数据统计工作。
1、取一个Integer值组成的集合中的最小值
public static void Test(String[] args){
List<Integer> list = Arrays.asList(32,32,32,1,2,12,1,23,34,34,32);
Optional<Integer> min = list.stream().min(Comparator.comparing(Integer::intValue));
System.out.println(min.get());
}
结果:
1
2、取一个Integer值组成的集合中的最大值
public static void Test(String[] args){
List<Integer> list = Arrays.asList(32,32,32,1,2,12,1,23,34,34,32);
Optional<Integer> max = list.stream().max(Comparator.comparing(Integer::intValue));
System.out.println(max.get());
}
结果:
34
3、取一组Dog中年龄最大的Dog
public static void Test(String[] args){
/* 使用上述集合 */
Optional<Dog> max = list.stream().max(Comparator.comparing(Dog::getAge));
System.out.println(max.get());
}
结果:
name: alisa age: 8 sex: female
4、取一组Integer值组成的集合中值大于30的值的个数
public static void Test(String[] args){
List<Integer> list = Arrays.asList(32,32,32,1,2,12,1,23,34,34,32);
long max = list.stream().filter(e -> e > 30).count();
System.out.println(max);
}
结果:
6
public class StreamUtils {
/**
* 集合为空,创建空的Stream流;否则创建集合的Stream流
* 避免出现空指针
*
* @param collection 集合
* @param 集合元素的泛型
* @return Stream对象
*/
private static <T> Stream<T> streamOf(Collection<T> collection) {
return CollectionUtils.isEmpty(collection) ? Stream.empty() : collection.stream();
}
/**
* 按照映射规则映射成一个新的集合流
*
* @param list 集合
* @param mapper 集合属性元素
* @param 函数输入类型的泛型
* @param 函数结果类型的泛型
* @return 新的集合
*/
public static <T, R> List<R> mapList(List<T> list, Function<? super T, ? extends R> mapper) {
return streamOf(list).map(mapper).collect(Collectors.toList());
}
/**
* 根据给定的条件进行筛选,将符合条件的元素提取成新的流
*
* @param list 集合
* @param predicate 筛选规则
* @param 流元素的类型
* @return 符合条件的流集合
*/
public static <T> List<T> filter(List<T> list, Predicate<? super T> predicate) {
return streamOf(list).filter(predicate).collect(Collectors.toList());
}
/**
* 根据给定的条件进行筛选,将符合条件的元素提取成新的流
*
* @param list 集合
* @param predicates 多个筛选条件
* @param 流元素的类型
* @return 符合条件的流集合
*/
@SafeVarargs
public static <T> List<T> filters(List<T> list, Predicate<? super T> ... predicates) {
Stream<T> stream = streamOf(list);
for (Predicate<? super T> predicate : predicates) {
stream = stream.filter(predicate);
}
return stream.collect(Collectors.toList());
}
/**
* 根据指定元素对集合进行升序排序
*
* @param list 集合
* @param keyExtractor 用来排序的元素
* @param 函数输入类型的泛型
* @param 函数结果类型的泛型
* @return 排序后的集合
*/
public static <T, U extends Comparable<? super U>> List<T> sorted(
List<T> list, Function<? super T, ? extends U> keyExtractor) {
return streamOf(list).sorted(Comparator.comparing(keyExtractor)).collect(Collectors.toList());
}
/**
* 根据指定元素对集合进行升序排序
*
* @param list 集合
* @param keyExtractor 用来排序的元素
* @param limit 排序后集合中保留的数量
* @param 函数输入类型的泛型
* @param 函数结果类型的泛型
* @return 排序后的集合
*/
public static <T, U extends Comparable<? super U>> List<T> sorted(
List<T> list, Function<? super T, ? extends U> keyExtractor, Integer limit) {
return streamOf(list).sorted(Comparator.comparing(keyExtractor)).limit(limit).collect(Collectors.toList());
}
/**
* 根据指定元素对集合进行降序排序
*
* @param list 集合
* @param keyExtractor 用来排序的元素
* @param 函数输入类型的泛型
* @param 函数结果类型的泛型
* @return 排序后的集合
*/
public static <T, U extends Comparable<? super U>> List<T> sortedDesc(
List<T> list, Function<? super T, ? extends U> keyExtractor) {
return streamOf(list).sorted(Comparator.comparing(keyExtractor).reversed()).collect(Collectors.toList());
}
/**
*根据规则判断元素是否匹配
*
* @param list 集合
* @param predicate 匹配规则
* @param 元素类型
* @return 匹配结果
*/
public static <T> boolean anyMatch(List<T> list, Predicate<? super T> predicate) {
return streamOf(list).anyMatch(predicate);
}
/**
* 将List集合转换成Map集合,同一个key时对value进行去重,保留第一个出现的value值
*
* @param list 集合
* @param keyMapper 新的Map中的key
* @param 参数的类型
* @return 转换后的Map集合
*/
public static <T, K> Map< K, T> toMapDistinctFirst(List<T> list, Function<? super T, ? extends K> keyMapper) {
return streamOf(list).collect(Collectors.toMap(keyMapper, Function.identity(), (key1, key2) -> key1));
}
/**
* 将List集合转换成Map集合,同一个key时对value进行去重,保留最后出现的value值
*
* @param list 集合
* @param keyMapper 新的Map中的key
* @param 参数的类型
* @return 转换后的Map集合
*/
public static <T, K> Map<K, T> toMapDistinctLast(List<T> list, Function<? super T, ? extends K> keyMapper) {
return streamOf(list).collect(Collectors.toMap(keyMapper, Function.identity(), (key1, key2) -> key2));
}
/**
* 将List转换为指定key->value键值对元素的Map集合
* @param list 集合
* @param keyMapper Map的key元素
* @param valueMapper Map的value元素
* @param 函数输入的类型
* @param 函数输出的类型
* @param 函数输出的类型
* @return 转换后的Map集合
*/
public static <T, K, U> Map<K, U> toMap(List<T> list, Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper) {
return streamOf(list).collect(Collectors.toMap(keyMapper, valueMapper));
}
}