点这里
Stream作为jdk8的一种重要特性,我们应该了解多一些。
为什么会有Stream?
在Stream出现之前,我们对集合中的元素进行一些操作需要先遍历每个元素再进行操作。如:
LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<String, Integer>();
linkedHashMap.put("1", 1);
linkedHashMap.put("2", 2);
linkedHashMap.put("3", 3);
linkedHashMap.put("4", 4);
LinkedHashMap<String, Integer> linkedHashMap2 = new LinkedHashMap<String, Integer>();
for (Entry entry : linkedHashMap.entrySet()) {
int v = (int)entry.getValue();
linkedHashMap2.put((String)entry.getKey(), v*2);
}
//结果:
//[1=1, 2=2, 3=3, 4=4]
//[1=2, 2=4, 3=6, 4=8]
在1.8我们怎么实现呢?
HashMap<String, Integer> hashMap = (HashMap<String, Integer>) linkedHashMap
.entrySet()
.stream()
.collect(
Collectors.toMap(a -> a.getKey(), a -> a.getValue() * 2));
System.out.println(hashMap.entrySet());
//[1=2, 2=4, 3=6, 4=8]
当你熟练掌握stream用法时,对集合的操作就很方便简单了。
什么是Stream?
点这里
Stream 是用函数式编程方式在集合类上进行复杂操作的工具,其集成了Java 8中的众多新特性之一的聚合操作,开发者可以更容易地使用Lambda表达式,并且更方便地实现对集合的查找、遍历、过滤以及常见计算等。
集合讲的是数据,流讲的是计算
1> Stream 自己不会存储元素
2> Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
3> Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
Stream 的操作三个步骤
1> 创建 Stream : 一个数据源 (如 : 集合、数组), 获取一个流
2> 中间操作 : 一个中间操作链,对数据源的数据进行处理
3> 终止操作(终端操作) : 一个终止操作,执行中间操作链,并产生结果
创建流:
- collection中扩展了default 方法
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
collection.stream()
collection.parallelStream()
- Arrays 类中增加了 stream() 静态方法
public static <T> Stream<T> stream(T[] array) {
return stream(array, 0, array.length);
}
Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5, 6);
int [] a = {1,2,3};
IntStream aStream= Arrays.stream(a);
还有几种创建方法我没有掌握,读者可以点击上面的连接查看。
Stream的操作
操作类型 | 接口方法 |
---|---|
中间操作 | concat() distinct() filter() flatMap() limit() map() peek()skip() sorted() parallel() sequential() unordered() |
结束操作 | allMatch() anyMatch() collect() count() findAny() findFirst() forEach() forEachOrdered() max() min() noneMatch() reduce() toArray() |
- 1 中间操作
方 法 | 描 述 |
---|---|
切片 | |
filter(Predicate p) | 接收 Lambda , 从流中排除某些元素 |
distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 |
limit(long maxSize) | 保留前n个 |
skip(long n) | 去掉前n个 |
映射 | |
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
排序 | |
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
我们来写一些例子加深印象,由于是中间方法所以在结尾加了foreach(终止方法)
//原数据
List<String> arrayList =Arrays.asList("1","2","3","3","4","5");
List<String> arrayList2 = Arrays.asList("a", "b", "c", "d", "e", "f");
- 切片型
过滤filter
arrayList.stream().filter(e->e.equals("3")).forEach(System.out::println);
//3 3
删除重复distinct
arrayList.stream().distinct().forEach(System.out::println);
//1 2 3 4 5
筛选limit
arrayList.stream().limit(3).forEach(System.out::println);
//1 2 3
跳过skip
arrayList.stream().skip(4).forEach(System.out::println);
//4 5
- 映射型
map
arrayList.stream().map(e->e+"A").forEach(System.out::println);
//1A 2A 3A 3A 4A 5A
mapToInt/mapToDouble/mapToLong
arrayList.stream().mapToInt(e -> Integer.parseInt(e))
.filter(e -> e==3).forEach(System.out::println);
//3 3
flatMap
Stream.of(arrayList, arrayList2).flatMap(u -> u.subList(0, 2).stream())
.forEach(System.out::println);
//1 2 a b
- 排序型
sorted
List<String> arrayList3 = Arrays.asList("9", "2", "3", "3", "4", "1");
arrayList3.stream().sorted().forEach(System.out::println);
// 1 2 3 3 4 9
arrayList3.stream().sorted((x, y) -> {
return x.compareTo(y);
}).forEach(System.out::println);
// 1 2 3 3 4 9
我好像对compareto,compareable,comparetor 是不是很懂,明天整理下
- 2 终止操作
方 法 | 描 述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反, Stream API 使用内部迭代) |
归纳 | |
reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值,返回 T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值,返回 Optional |
收集 | |
collect(Collector c) | 将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法 |
我们再来对终止操作进行举例:
reduce 将元素值结合起来
String sum = arrayList.stream().reduce( "",(x,y)->(x+y) );
Optional<String> sum2 = arrayList.stream().reduce((x,y)->(x+y) );
System.out.println( "Sum: "+sum+" Sum2: "+ sum2 );
//Sum: 123345 Sum2: Optional[123345]
anymatch/allmatch/nomatch
boolean flag = arrayList.stream().anyMatch(e->e.equals("1"));
System.err.println(flag);
// true
count
long num = arrayList.stream().count();
System.err.println("num: "+num+" size: "+arrayList.size());
collection
Map<String, List<String> > resultmap=arrayList.stream().collect(Collectors.groupingBy(e->{
if ( e.equals("1") ) {
return "ok";
}
else {
return e;
}
}));
for (Entry entry : resultmap.entrySet()) {
System.out.println(entry.getKey()+" "+entry.getValue());
}
//2 [2]
//3 [3, 3]
//4 [4]
//5 [5]
//ok [1]