Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
特点:
不是数据结构,不会保存数据
不会修改原来的数据源,他会将操作后的数据保存到另一个对象中;(peek方法可以修改流中的元素)
惰性求值,流在中间处理过程中,只对操作进行了记录,并不会立即执行,需要等到执行中止操作时才会进行实际的计算
代码简洁,函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环
多核友好,Java 函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下方法
- Collectors:Java8中Collectors详解
- Collator: 初步认识Collator
- Collections:Java 之 Collections 工具类
- Comparator:Java Comparator接口
- 第一步:把集合转换为流***stream***
- 第二步:操作***stream***流
stream流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果
4.1、使用Collection下的 stream() 和 parallelStream() 方法
List<String> list = new ArrayList<>();
//获取一个顺序流
Stream<String> stream = list.stream();
//获取一个并行流
Stream<String> parallelStream = list.parallelStream();
4.2、使用Arrays 中的 stream() 方法,将数组转成流
Integer[] nums = new Integer[]{1,2,3,4,5,6,8};
Stream<Integer> stream = Arrays.stream(nums);
stream.forEach(System.out::println);
4.3、使用Stream中的静态方法:of()、iterate()、generate()
String[] strings = {"a","b","c"};
Stream.of(strings).forEach(System.out::println);
System.out.println("================================================");
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
stream.forEach(System.out::println);
System.out.println("================================================");
Stream<User> userStream = Stream.of(new User(10),new User(21),new User(19));
userStream.forEach(item->System.out.println(item.getAge()));
System.out.println("================================================");
/**
* 根据函数生成流:无限流,一定要加limit
* @author hubz
* @date 2020/8/7 16:50
* @param seed:初始值
* @param 参数二:函数
**/
Stream<Integer> stream2 = Stream.iterate(1, (x) -> x + 2).limit(10);
stream2.forEach(System.out::println); // 1 3 5 7 9
System.out.println("================================================");
/**
*
* 1.这种情形通常用于随机数、常量的 Stream,或者需要前后元素间维持着某种状态信息的 Stream。
* 2.把 Supplier 实例传递给 Stream.generate() 生成的 Stream,默认是串行(相对 parallel 而言)
* 但无序的(相对 ordered 而言)
*
* @author hubz
* @date 2020/8/7 17:07
**/
Stream<Integer> stream3 = Stream.generate(()->new Random().nextInt()).limit(3);
stream3.forEach(System.out::println);
System.out.println("================================================");
Stream.generate(()->new Random().nextInt(24)).limit(3).forEach(System.out::println);
class User{
int age;
public User(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
4.4、使用 BufferedReader.lines() 方法,将每行内容转成流
BufferedReader reader = new BufferedReader(new FileReader("E:\\test_stream.txt"));
Stream<String> lineStream = reader.lines();
lineStream.forEach(System.out::println);
4.5、使用 Pattern.splitAsStream() 方法,将字符串分隔成流
Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
stringStream.forEach(System.out::println);
测试过程中使用到的对象
User
class User {
int age;
int heigh;
public User(int age, int heigh) {
this.age = age;
this.heigh = heigh;
}
public User(int age) {
this.age = age;
}
public User() {
}
public int getHeigh() {
return heigh;
}
public void setHeigh(int heigh) {
this.heigh = heigh;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", heigh=" + heigh +
'}';
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
BillsNums
class BillsNums {
private String id;
private int nums;
private int sums;
public BillsNums() {
}
public BillsNums(int nums) {
this.nums = nums;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getNums() {
return nums;
}
public void setNums(int nums) {
this.nums = nums;
}
public int getSums() {
return sums;
}
public void setSums(int sums) {
this.sums = sums;
}
@Override
public String toString() {
return "BillsNums{" +
"id='" + id + '\'' +
", nums=" + nums +
", sums=" + sums +
'}';
}
}
用于通过设置的条件过滤出元素
/**
* @desc filter中间操作符:过滤集合中不符合条件的元素
* @author hubz
* @date 2020/8/6 23:30
*/
public static void filter(){
List<String> strings = Arrays.asList("123","dsa2","das","sda","65");
List<String> res = strings.stream().filter(item->{
if(item.contains("a")){
System.out.println("包含a的元素:"+item);
return true;
}
System.out.println(item);
return false;
}).collect(Collectors.toList());
res.forEach(System.out::println);
}
通过流中元素的 hashCode() 和 equals() 去除重复元素
对象去重、求最小值、求最大值
/**
* @desc distinct:去除集合中的重复
* @author hubz
* @date 2020/8/6 23:36
*/
public static void distinct(){
List<String> strings = Arrays.asList("123","dsa2","dsa2","sda","123","65");
List<String> distincted = strings.stream().distinct().collect(Collectors.toList());
distincted.forEach(System.out::println);
List<User> users = new ArrayList<>();
users.add(new User(1));
users.add(new User(1));
users.add(new User(2));
users.stream().distinct().collect(Collectors.toList()).forEach(System.out::println);
}
返回一个不超过给定长度的流
/**
* limit获取流中的前n个元素
* @author hubz
* @date 2020/8/7 19:35
**/
private static void limit(){
List<String> strings = Arrays.asList("abc","bc","bc","efg","abcd","jkl");
strings.stream().limit(3).collect(Collectors.toList())
.forEach(System.out::println);
}
返回一个跳过前n个元素的流
/**
* skip获取流中除去前n个元素的其他所有元素
* @author hubz
* @date 2020/8/7 19:36
**/
private static void skip(){
List<String> strings = Arrays.asList("abc","bc","bc","efg","abcd","jkl");
strings.stream().skip(2).collect(Collectors.toList())
.forEach(System.out::println);
}
接受一个函数作为参数,这个函数会被应用到每个元素上,并将其映射成一个新的元素
/**
* @desc 对流中所有数据进行处理
* @author hubz
* @date 2020/8/7 0:00
*/
public static void map(){
List<String> strings = Arrays.asList("123","dsa2","dsa2","sda","123","65");
strings.stream().map(item -> {
return item.concat("_HAHA");
}).collect(Collectors.toList()).forEach(System.out::println);
System.out.println("===========================================");
List<String> res = new ArrayList<>();
strings.forEach(item->{
item = item+"_das_ASSAS";
res.add(item);
});
res.forEach(System.out::println);
}
扁平化处理:各个数组不是分别映射成一个流而是映射成流的内容。
接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
public static void flatMap() {
Stream.of(new String[]{"Hello", "World"})
.flatMap(str -> Arrays.stream(str.split("")))
.distinct()//去重
.collect(Collectors.toList())
.forEach(System.out::println);
Stream.of("beijing huanying ni")
.flatMap(str -> Arrays.stream(str.split(" ")))
.collect(Collectors.toList())
.forEach(System.out::println);
}
map和flatMap的对比
public static void mapAndflatMap(){
Stream.of(new String[]{"Hello", "World"})
.flatMap(str -> Arrays.stream(str.split("")))
.distinct()//去重
.collect(Collectors.toList())
.forEach(System.out::println);
System.out.println("====================================");
Stream.of(new String[]{"Hello", "World"})
.map(str -> Arrays.stream(str.split("")))
.distinct()//去重
.collect(Collectors.toList())
.forEach(s->s.forEach(System.out::println));
}
map:对流中每一个元素进行处理
flatMap:流扁平化,让你把一个流中的“每个值”都换成另一个流,然后把所有的流连接起来成为一个流;
总结:map是对每一个元素进行操作,flatmap是对二级元素进行操作。
本质区别:map返回一个值,flatmap返回一个流,多个值;
应用场景:
返回排序后的流,默认按照字母序
/**
* 将数据排序
* @author hubz
* @date 2020/8/8 9:18
**/
public static void sorted(){
//----------------------- 字母排序 -----------------------
List<String> strings = Arrays.asList("abc","bcd","acd","eds");
strings.stream().sorted().forEach(System.out::println);
System.out.println("==============================");
//----------------------- 数字排序 -----------------------
List<Integer> list = Arrays.asList(3, 2, 1, 4);
List<Integer> resList = list.stream().sorted().collect(Collectors.toList());
resList.forEach(System.out::println);
System.out.println("==============================");
//----------------------- 根据对象属性排序 -----------------------
List<User> userList = new ArrayList<>();
userList.add(new User(12));
userList.add(new User(52));
userList.add(new User(20));
userList.forEach(System.out::println);
System.out.println("==============================");
userList.stream().sorted(Comparator.comparing(User::getAge)).forEach(System.out::println);
System.out.println("==============================");
//----------------------- 汉字排序 -----------------------
//反向排序
List<String> nameList = Arrays.asList("张伟", "李四", "钱王对", "诸葛询");
nameList.stream().sorted(Collections.reverseOrder(Collator.getInstance(Locale.CHINA)))
.forEach(System.out::println);
//正向排序
List<String> nameList = Arrays.asList("张伟", "李四", "钱王对", "诸葛询");
nameList.stream().sorted(Collator.getInstance(Locale.CHINA)).
collect(Collectors.toList()).forEach(System.out::println);
}
如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值;
- peek对
对象
操作会有效果;- peek主要用于debug操作;
public static void peek(){
User user1 = new User(12);
User user2 = new User(20);
List<User> users = Arrays.asList(user1,user2);
users.stream().peek(o->{
o.setAge(100);
}).collect(Collectors.toList()).forEach(System.out::println);
System.out.println("===========================================");
Stream.of("one", "two", "three","four").filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());//.forEach(System.out::println);
}
突发奇想:
public static void peek(){
User user1 = new User(12);
User user2 = new User(20);
List<User> users = Arrays.asList(user1,user2);
long sum = users.stream()
.peek(o -> {o.setAge(o.getAge() / 2);})//对年龄除2
.mapToInt(User::getAge)
.summaryStatistics().getSum();//求和
System.out.println(sum);
}
- mapToInt
- mapToLong
- mapToDouble
- flatMapToInt
- flatMapToLong
- flatMapToDouble
mapToT方法,T表示基础数据类型,包括int,long,double,注意没有float。mapToT方法返回值是TStream类型,例如
IntStream
,TStream类包含了一些处理基础数据的方法,可以让我们更方便。我们使用mapToT的原因,不仅仅是方便,还在于性能。我们知道,因为泛型的原因,可以有List但是不能有List,这里的IntStream就相当于是List,int 所占内存比Integer小。flatMapToInt()这种flatMapToT(),这里的T同样表示int long double基础数据类型。
检测是否至少匹配一个元素,返回boolean
/**
* @desc 集合中是否有一个元素满足条件
* @author hubz
* @date 2020/8/9 22:44
*/
public static void anyMatch(){
List<String> stringList = Arrays.asList("abc","bcd","edc","rsfdas","ufhb");
boolean bc = stringList.stream().anyMatch(s->s.contains("bc"));
System.out.println("anyMatch 有满足的:"+bc);//有满足的;true
boolean z = stringList.stream().anyMatch(s -> s.contains("z"));
System.out.println("anyMatch 都不满足:"+z);//都不满足:false
}
检查是否匹配所有元素,返回boolean
/**
* @desc 集合中元素是否都满足条件
* @author hubz
* @date 2020/8/9 23:02
*/
public static void allMatch(){
List<String> stringList = Arrays.asList("abc","bcd","edc","rsfdas","ufhb");
boolean b = stringList.stream().allMatch(str -> str.length() > 0);
System.out.println("allMatch 都满足:"+b);//都满足:true
boolean b1 = stringList.stream().allMatch(str -> str.length() > 3);
System.out.println("allMatch 有不满足的:"+b1);//有不满足的:false
}
检查是否没有匹配所有元素,返回boolean
/**
* @desc 集合中元素是否都不满足条件
* @author hubz
* @date 2020/8/9 23:03
*/
public static void noneMatch(){
List<String> stringList = Arrays.asList("abc","bcd","edc","rsfdas","ufhb");
boolean a = stringList.stream().noneMatch(str -> str.contains("a"));
System.out.println("noneMatch 有满足的:"+a);//有满足的:false
boolean z = stringList.stream().noneMatch(str -> str.contains("z"));
System.out.println("noneMatch 都不满足:"+z);//都不满足:true
}
将返回当前流中的任意元素
/**
* @desc 返回集合中的任意元素
* @author hubz
* @date 2020/8/9 23:03
*/
public static void findAny(){
List<String> stringList = Arrays.asList("abc","bcd","edc","rsfdas","ufhb");
String s = stringList.stream().findAny().get();
System.out.println(s);
System.out.println("=================================");
for(int i=0;i<10000;i++){
System.out.println(stringList.parallelStream().findAny().orElse("-1"));
}
}
返回流中的第一个元素
/**
* @desc 返回集合中的第一个元素
* @author hubz
* @date 2020/8/9 23:04
*/
public static void findFirst(){
List<String> stringList = Arrays.asList("abc","bcd","edc","rsfdas","ufhb");
String s = stringList.stream().findFirst().get();
System.out.println(s);
System.out.println("=================================");
for(int i=0;i<10000;i++){
System.out.println(stringList.parallelStream().findFirst().orElse("-1"));
}
}
遍历流:没啥好说的
收集器:将流转化为其他形式
/**
* @desc collect 将流转换成其他形式
* @author hubz
* @date 2020/8/9 23:23
*/
public static void collect() {
List<String> stringList = Arrays.asList("abc", "bcd", "abc", "edc", "rsfdas", "ufhb");
stringList.stream()
.collect(Collectors.toSet())
.forEach(System.out::println);
System.out.println("============================");
AtomicInteger i = new AtomicInteger();
Map<String, String> stringMap = stringList.stream()
.collect(Collectors.toMap(String::toUpperCase, v -> {
i.getAndIncrement();
return v.concat("_value" + i);
}, (k, v) -> k));
System.out.println(stringMap);
System.out.println("============================");
AtomicInteger j = new AtomicInteger();
Map<String, String> stringMap1 = stringList.stream()
.collect(Collectors.toMap(k->k.toUpperCase(), v -> {
j.getAndIncrement();
return v.concat("_value" + j);
}, (k, v) -> v));
System.out.println(stringMap1);
//Collectors.toMap(keyMapper,valueMapper,mergeFunction,mapFactory)
//参数1:key值映射
//参数2:value值映射
//参数3:当出现key值相同时,选取前面/后面的作为value值,就是出现相同key时的选择方式
//参数4:默认返回的map类型为HashMap,可以自己返回不同的map实现
System.out.println("============================");
//对象操作更清晰
List<User> userList = Arrays.asList(
new User(12,170),
new User(12,180),
new User(22,175),
new User(25,180)
);
Map<Integer, Integer> userMap = userList.stream()
.collect(Collectors.toMap(User::getAge, User::getHeigh, (k, v) -> v));
System.out.println(userMap);//12 的 170 被 180 覆盖
System.out.println("============================");
userMap = userList.stream().collect(Collectors.toMap(User::getAge, User::getHeigh, (k, v) -> k));
System.out.println(userMap);//12 的 170 未被 180 覆盖
}
可以将流中的元素反复结合起来,得到一个值
public static void reduce(){
int[] arr = {1,2,3,5,2,2,4,8};
//求和
//一个参数
int sum = Arrays.stream(arr).reduce(Integer::sum).getAsInt();
System.out.println(sum);
System.out.println("============================");
/**
* @desc 两个参数
* @author hubz
* @param identity:初始值,在初始值的基础上进行计算
* 方法的返回结果为初始值identity类型的对象
* @date 2020/8/10 10:50
**/
int sum1 = Arrays.stream(arr).reduce(10, Integer::sum);
System.out.println(sum1);
System.out.println("============================");
/**
* @desc
* ① U类型的初始值。
* ② (T,U)→U,T+U返回U类型。
* ③ 组合器(T,T)→T,T+T返回T类型
*
* @author hubz
* @date 2020/8/10 10:49
**/
int mul = Arrays.stream(arr).reduce(1, (x, y) -> x * y);
System.out.println(mul);
System.out.println("============================");
//非并行
List<Integer> num = Arrays.asList(1, 2, 3, 4, 5, 6);
ArrayList<Integer> arr0 = new ArrayList<>();
arr0.add(7);
arr0.add(8);
arr0.add(9);
arr0.add(10);
List<Integer> reduce = num.stream().reduce(arr0, (x, y) -> {
x.add(y);
return x;
}, (List<Integer> x, List<Integer> y) -> {
System.out.println("并行才会出现");
return x;
});
System.out.println(reduce);
System.out.println("============================");
//并行
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer num1 = nums.parallelStream().reduce(0, (x, y) -> x + y, (x, y)->{
System.out.println("这里调用一次");
return x + y;
});
System.out.println(num1);
}
返回流中元素的个数
/**
* @desc 返回流中元素的个数
* @author hubz
* @date 2020/8/9 23:24
*/
public static void count() {
List<String> stringList = Arrays.asList("abc", "bcd", "edc", "rsfdas", "ufhb");
System.out.println(stringList.stream().count());
}
返回最小值
返回最大值
求和,平均值,最大值,最小值
/**
* @desc 求平均值
* @author hubz
* @date 2020/8/9 14:10
*/
public static void avg(){
Double[] list = {0.69D, 1D, 1.2, 5.6};
double[] doubles = {0.15D,2D,2.3,93.1};
List<Integer> integers = Arrays.asList(0, 1, 2, 56);
//求平均值
Double avgDouble = Arrays.stream(list).collect(Collectors.averagingDouble(Double::doubleValue));
System.out.println("平均值为 avgDouble:"+avgDouble.intValue());
double avgDouble1 = Arrays.stream(list).mapToDouble(Double::doubleValue).average().orElse(0D);
System.out.println("平均值为 avgDouble1:"+(int)avgDouble1);
double avgDouble2 = Arrays.stream(doubles).average().orElse(0D);
System.out.println("平均值为 avgDouble2:"+ (int) avgDouble2);
double avgDouble3 = Arrays.stream(list).mapToDouble(Double::doubleValue)
.summaryStatistics().getAverage();
System.out.println("平均值为 avgDouble3:"+ (int) avgDouble3);
double intAvg = integers.stream().mapToInt(Integer::intValue).average().orElse(0);
System.out.println("平均值为 intAvg:"+intAvg);
}
/**
* @desc 求最小值
* @author hubz
* @date 2020/8/9 14:11
*/
public static void min(){
Double[] list = {0.69D, 1D, 1.2, 5.6};
double[] doubles = {0.15D,2D,2.3,93.1};
List<Integer> integers = Arrays.asList(0, 1, 2, 56);
//求最小值
Double minDouble = Arrays.stream(list).min(Double::compare).get();
System.out.println("最小值为 minDouble:"+minDouble);
Double minDouble1 = Arrays.stream(list).min(Double::compareTo).get();
System.out.println("最小值为 minDouble1:"+minDouble1);
double minDouble2 = Arrays.stream(doubles).min().getAsDouble();
System.out.println("最小值为 minDouble2:"+minDouble2);
double minDouble3 = Arrays.stream(list).mapToDouble(Double::doubleValue)
.summaryStatistics().getMin();
System.out.println("最小值为 minDouble3:"+minDouble3);
Integer minInteger = integers.stream().min(Integer::compare).get();
System.out.println("最小值为 minInteger:"+minInteger);
}
/**
* @desc 求最大值
* @author hubz
* @date 2020/8/9 14:19
*/
public static void max(){
Double[] list = {0.69D, 1D, 1.2, 5.6};
double[] doubles = {0.15D,2D,2.3,93.1};
List<Integer> integers = Arrays.asList(0, 1, 2, 56);
//求最大值
Double maxDouble = Arrays.stream(list).max(Double::compare).get();
System.out.println("最大值为 minDouble:"+maxDouble);
Double maxDouble1 = Arrays.stream(list).max(Double::compareTo).get();
System.out.println("最大值为 minDouble1:"+maxDouble1);
double maxDouble2 = Arrays.stream(doubles).max().getAsDouble();
System.out.println("最大值为 maxDouble2:"+maxDouble2);
double maxDouble3 = Arrays.stream(list).mapToDouble(Double::doubleValue)
.summaryStatistics().getMax();
System.out.println("最大值为 maxDouble3:"+maxDouble3);
int maxInteger = integers.stream().max(Integer::compareTo).get();
System.out.println("最大值为 maxInteger:"+maxInteger);
}
/**
* @desc 求和
* @author hubz
* @date 2020/8/9 14:20
*/
public static void sum(){
Double[] list = {0.69D, 1D, 1.2, 5.6};
double[] doubles = {0.15D,2D,2.3,93.1};
List<Integer> integers = Arrays.asList(0, 1, 2, 56);
// 求和
double sum = Stream.of(list).mapToDouble(Double::doubleValue).sum();
System.out.println("和为 sum:"+sum);
double sum1 = Stream.of(list).mapToDouble(Double::doubleValue).summaryStatistics().getSum();
System.out.println("和为 sum1:"+sum1);
double sum2 = Arrays.stream(doubles).sum();
System.out.println("和为 sum2:"+sum2);
Integer sumInt = integers.stream().reduce(0,Integer::sum);
System.out.println("和为 sumInt:"+sumInt);
Integer sumInt1 = integers.stream().reduce(Integer::sum).get();
System.out.println("和为 sumInt1:"+sumInt1);
}
/**
* @desc 对象操作
* @author hubz
* @date 2020/8/9 13:24
*/
public static void testO() {
List<BillsNums> billsNums = Arrays.asList(
new BillsNums(1),
new BillsNums(2),
new BillsNums(4)
);
//求平均值
int avgNum = billsNums.stream().collect(Collectors.averagingDouble(BillsNums::getNums)).intValue();
System.out.println("平均值求法1:"+avgNum);
avgNum = (int)billsNums.stream().mapToInt(BillsNums::getNums).summaryStatistics().getAverage();
System.out.println("平均值求法2:"+avgNum);
int asDouble = (int)Math.floor(billsNums.stream().mapToDouble(BillsNums::getNums)
.average().orElse(0D));
System.out.println("平均值求法3"+ asDouble);
//根据这两个即可看出,对象和Double类似,其中方法均可使用
}