概述
Java 8引入的Stream API用于对集合(如列表、集合等)进行函数式操作(如过滤、映射、规约等)。这类流提供了一种高效且易读的方式来处理集合中的数据。
获取Stream对象的方式有哪些个?
1 Stream接口提供的: of静态方法
public static<T> Stream<T> of(T... values) { // 传入一些T类型数据;
return Arrays.stream(values);
}
public static<T> Stream<T> ofNullable(T t) {
return t == null ? Stream.empty()
: StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}
public static<T> Stream<T> of(T t) {
return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}
2 集合当中stream()方法
List/Set
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
3 数组工具类Arrays.stream(T[] t)
public static <T> Stream<T> stream(T[] array) {
return stream(array, 0, array.length);
}
4 基本使用
大体分为两大类方法:
中间方法「返回值本身还是一个Stream对象,支持链式调用」
终结方法,它不支持链式调用的.
集合的操作.通过以下方法获取Stream对象;
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
package com.tingyi.demo04;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author 听忆
* Stream流基本应用:
*/
public class Test01 {
public static void main(String[] args) {
// 搞一个集合.对集合元素进行操作;
List<String> nameList = new ArrayList<>();
nameList.add("张三");
nameList.add("张三");
nameList.add("张三");
nameList.add("张三");
nameList.add("张三");
nameList.add("李四");
nameList.add("王五");
nameList.add("赵六");
nameList.add("田七");
nameList.add("孙八");
// ①. 获取Stream对象;
Stream<String> stream = nameList.stream();
// 获取一下集合当中名称是姓张的.
// 过滤集合元素.
// Predicate<? super T> predicate = s -> {
// // 判断集合元素的逻辑写在这里.返回是一个boolean值;
// if(s.contains("张")){
// return true;
// }
// return false;
// };
// 应用了lambda表达式来简化操作
// 本质: 匿名内部类对象.
// 本质: 匿名内部类对象. --> 真理.
List<String> list = stream.filter(s -> s.contains("张三"))
.collect(Collectors.toList());
System.out.println(list);
}
}
一个重点:
当一个接口当作方法的参数的时候,实参传入的就是:
实现了这个接口的实现类的对象
当一个接口当作了方法的返回值,那么返回的一定是:
实现了这个接口的实现类的对象
方法名称 | 描述 | 方法类型 |
---|---|---|
filter | 针对于每个元素进行判断,符合条件的留下,不符合过滤掉了. | 中间方法 |
map | 把一个数据类型转换为别外一个数据类型. | 中间方法 |
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
package com.tingyi.demo04;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author 听忆
*/
public class Test02 {
public static void main(String[] args) {
List<String> nameList = new ArrayList<>();
nameList.add("张三");
nameList.add("张三");
nameList.add("张三");
nameList.add("张三");
nameList.add("张三");
nameList.add("李四");
nameList.add("王五");
nameList.add("赵六");
nameList.add("田七");
nameList.add("孙八");
// 想在这个集合当中,给所有的元素都添加一个字符串,"好好学习, 天天向上!"
// 张三-好好学习, 天天向上;
Stream<String> stream = nameList.stream(); // Stream对象.
List<String> newList = stream.map(s -> s + "-好好学习, 天天向上!")
.collect(Collectors.toList());
System.out.println(newList);
// Stream特性: 一次性的对象.用完之后,不能重复使用.如果你还要用,自己搞对象;
// Stream特性: 一次性的对象.用完之后,不能重复使用.如果你还要用,自己搞对象;
// Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
List<String> list1 = nameList.stream().filter(s -> s.contains("李四")).collect(Collectors.toList());
System.out.println(list1);
System.out.println("--------------------------------");
// // 一步到位写法.
List<String> list = nameList.stream()
.map(s -> s + "hello world!")
.collect(Collectors.toList());
System.out.println(list);
}
}
①. Stream流,只能消费一次.不能重复使用;
如果重复使用则会抛出异常:
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
②. Function, t -> r, 这里使用的泛型,实际上咱们可以是同一个类型相互之间有转换;
5 将Stream还原成List/数组对象
Stream当中提供了方法:
<R, A> R collect(Collector<? super T, A, R> collector);// 参数: 实现好Collector接口的实现类的对象;
public interface Collector<T, A, R> {}
如果要自动手动实现,复杂度太高了,而且我们进行方法调用,必须得手写一个实现类。显然,这么做不太现实.jdk当中提供了工具类.
Collectors
static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
private final Supplier<A> supplier;
private final BiConsumer<A, T> accumulator;
private final BinaryOperator<A> combiner;
private final Function<A, R> finisher;
private final Set<Characteristics> characteristics;
// 实现类,是在Collectors当中的一个静态内部类.
public static <T>
Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
CH_ID);
}
上边的方法,它是定义在
Collectors
工具类当中的.还是一个静态的方法.方便我们直接使用类名调用.Stream流当中,collect(Collector),表示收集方法,就是将一个stream对象转换为其它集合姿势;所以我们在使用的时候,都会借助工具类.造成别自己去写实现类.
// Supplier, 生产型接口.这里我们生产啥类型的集合,就可以将Stream转换成啥类型的集合;
public static Collector toCollection(Supplier collectionFactory) {
return new CollectorImpl<>(collectionFactory, Collection<T>::add,
(r1, r2) -> { r1.addAll(r2); return r1; },
CH_ID);
}
将Stream流,还原一个指定的集合类型;
Supplier collectionFactory, 参数生产接口.没有入参,只有出参:
() -> { return new HashSet<>()}; –> 更改成方法引用.
// 将stream转换为字符串.
直接调用: Collectors.joining("分隔符");
Collectors.joining("分隔符", "前缀", "后缀");
// 示例:
String s = nameList.stream()
.collect(Collectors.joining(",", "{", "}"));
{张三,张三,张三,张三,张三,李四,王五,赵六,田七,tom,jack,jerry,rose,齐天大圣}
6 StringJoiner
String
StringBuffer
StringBuilder
// String s1 = new String(“hello” + “world”);
StringJoiner
public StringJoiner(CharSequence delimiter, // 分隔符
CharSequence prefix, // 前缀
CharSequence suffix) {} // 后缀
public StringJoiner(CharSequence delimiter) { // 分隔符
this(delimiter, "", "");
}
添加串, 通过add(),可以链式调用;
Collectors, 这里边封装了大量的常用方法,该方法返回值就是实现了Collector接口的实现类的对象;
Stream对象 —> Map集合.
toMap(Function f1, Function f2)
7 分组实现
collect(Collectors.groupBy(Function f)
package com.tingyi.demo05;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author 听忆
*/
public class Test01 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
User u1 = new User(1L, "张三小", "男", "河北");
User u2 = new User(15L, "tom", "男", "河北");
User u3 = new User(14L, "赵小四", "女", "北京");
User u4 = new User(13L, "马小六", "女", "北京");
User u5 = new User(12L, "jack", "女", "上海");
User u6 = new User(11L, "jerry", "女", "广州");
userList.add(u1);
userList.add(u2);
userList.add(u3);
userList.add(u4);
userList.add(u5);
userList.add(u6);
Map<String, List<User>> listMap = userList.stream()
.collect(Collectors.groupingBy(user -> user.getAddress()));
Set<Map.Entry<String, List<User>>> entries = listMap.entrySet();
for (Map.Entry<String, List<User>> entry : entries) {
String key = entry.getKey();
System.out.println(" key = " + key);
List<User> users = entry.getValue();
for (User user : users) {
System.out.println(user);
}
System.out.println("-----------------------------------------------------------------");
}
}
}
key,填入的是分组字段的值.
value, 将符合该分组的元素都存储到了List当中;
符合条件的分为一组, 不符合条件的分为一组;
package com.tingyi.demo05;
import javax.naming.Name;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author 听忆
*/
public class Test02 {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
User u1 = new User(1L, "张三小", "男", "河北");
User u2 = new User(15L, "tom", "男", "河北");
User u3 = new User(14L, "赵小四", "女", "北京");
User u4 = new User(13L, "马小六", "女", "北京");
User u5 = new User(12L, "jack", "女", "上海");
User u6 = new User(11L, "jerry", "女", "广州");
userList.add(u1);
userList.add(u2);
userList.add(u3);
userList.add(u4);
userList.add(u5);
userList.add(u6);
/**
* 将整个集合当中的分为两组.key = boolean值;
*/
Map<Boolean, List<User>> listMap = userList.stream()
.collect(Collectors.partitioningBy(user -> user.getSex().equals("男")));
// forEach
listMap.forEach((k, v) -> {
System.out.println("key = " + k);
v.forEach(System.out::println);
System.out.println("=====================================");
});
}
}
==总结分组实现==
前置条件都是在数据收集的时候去操作,也就是调用
collect
这个方法的时候,去操作分组的;
分为两组, 根据条件判断,符合条件的分为一组.不符合条件的分为另外的一组;
分为多组, 根据分组字段进行分组.符合字段要求的放到一个List集合.
8 聚合统计
方法如下所示:
package com.tingyi.demo06;
import java.util.ArrayList;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* @author 听忆
*/
public class Test {
public static void main(String[] args) {
List<Integer> numberList = new ArrayList<>();
numberList.add(10);
numberList.add(20);
numberList.add(314);
numberList.add(8);
numberList.add(90);
// ?????? Optional , Objects
Optional<Integer> optional = numberList.stream()
// .collect(Collectors.maxBy((i1, i2) -> i1 - i2));
.max((i1, i2) -> i1 - i2); // Stream流当中提供的方法,更加直观一些.推荐使用;
Integer result = optional.get();
System.out.println(result);
System.out.println("--------------------------------------------------");
IntSummaryStatistics statistics = numberList.stream()
.collect(Collectors.summarizingInt(i -> i));
System.out.println(statistics.getCount());
System.out.println(statistics.getAverage());
System.out.println(statistics.getMin());
System.out.println(statistics.getSum());
System.out.println(statistics.getMax());
}
}
System.out.println("------------------------------------------------");
LongSummaryStatistics summaryStatistics = userList.stream()
.collect(Collectors.summarizingLong(User::getId));// user -> user.getId();
System.out.println(summaryStatistics.getAverage());
System.out.println(summaryStatistics.getCount());
System.out.println(summaryStatistics.getMax());
System.out.println(summaryStatistics.getMin());
System.out.println(summaryStatistics.getSum());