首页 > 基础资料 博客日记
Java8新特性Stream流
2023-08-01 19:55:25基础资料围观227次
1、是什么?
- Stream(流)是一个来自数据源的元素队列并支持聚合操作
2、能干嘛?
- Stream流的元素是特定类型的对象,形成一个队列。
- Java中的Stream并不会存储元素,而是按需计算。
- 数据源,流的来源。
- 可以是集合,数组,I/O channel, generator等。
- 聚合操作,类似SQL语句一样的操作:
- 比如filter, map, reduce, find, match, sorted等。
- 和以前的Collection操作不同, Stream操作还有两个基础的特征:
- Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
- 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
3、怎么玩?
1、创建Stream的方式(原材料)
package com.qbb.threadpool;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-07-23 20:19
* @Description:
*/
public class Java8NewFeatureStream {
public static void main(String[] args) {
// 创建Stream方式一 : 通过集合
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
// 获取串行流
Stream<Integer> stream = list.stream();
// 获取一个并行流
Stream<Integer> parallelStream = list.parallelStream();
// 创建Stream方式二 : 通过数组
String[] arr = new String[]{"a", "b", "c"};
Stream<String> arrStream = Arrays.stream(arr);
// 创建Stream方式三 : 通过Stream.of()
Stream<String> streamOf = Stream.of("x", "y", "z");
// 创建Stream方式四 : 通过Stream.iterate(),创建无限流
Stream<Integer> integerStream = Stream.iterate(0, q -> q + 1).limit(5);
integerStream.forEach(System.out::println);
//生成10个随机数
Stream<Double> stream1 = Stream.generate(Math::random).limit(10);
stream1.forEach(System.out::println);
}
}
2、中间操作(车间加工)
(1)fifter(Predicate<? super T> predicate)
: 过滤,保留满足条件分元素
public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6);
asList.stream()
.filter(q -> q % 2 ==0) // filter:过滤,保留符合条件的元素
.forEach(System.out::println); // forEach:内部迭代,终止操作输出每一个元素
}
(2) distinct ()
: 去除重复的元素
// 测试类
class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age && Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 5);
asList.stream().distinct().forEach(System.out::println);
List<User> userList = new ArrayList<>();
// 测试一下对象类型
for (int i = 0; i < 5; i++) {
User user = new User("qiuqiu"+i,18+i);
userList.add(user);
}
User qiuqiu3 = new User("qiuqiu3", 21);
userList.add(qiuqiu3);
userList.stream().distinct().forEach(System.out::println);
}
(3)limit(long maxSize)
: 获取指定maxSize个元素
public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 5);
asList.stream().limit(3).forEach(System.out::println);
}
(4) skip(long n)
: 跳过前n个元素
public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 5);
long count = asList.stream()
.skip(3) // 跳过前三个元素
// .findFirst() // 获取跳过操作后的第一个元素
// .findAny() // 获取跳过操作后的任意一个元素
.count(); // 获取剩余元素个数
// System.out.println("result = " + result);
System.out.println("count = " + count);
}
(5) sorted()/sorted(Comparator<? super T> comparator)
: 排序
public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(4, 5, 6, 2, 1, 2, 3, 5);
// 默认排序
asList.stream().sorted().forEach(System.out::println);
System.out.println("=======================================================");
// 指定比较器排序
// asList.stream().sorted((o1,o2) -> o1.compareTo(o2)).forEach(System.out::println);
asList.stream().sorted(Integer::compareTo).forEach(System.out::println);
}
(6) map
:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(4, 5, 6, 2, 1, 2, 3, 5);
// map
asList.stream().map(q -> {
String str;
if(q%2 == 0){
str = q+"qiu";
}else {
str = q + "ll";
}
return str;
}).forEach(System.out::println);
}
- 其他的一些操作
mapToInt(ToIntFunction<? super T> mapper)
mapToDouble(ToDoubleFunction<? super T> mapper)
mapToLong(ToLongFunction<? super T> mapper)
flatMapToInt(Function<? super T, ? extends IntStream> mapper)
flatMapToLong(Function<? super T, ? extends LongStream> mapper)
flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper)
(7) flatMap
:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
public static void main(String[] args) {
// 创建流
String[] arr = new String[]{"a,b,c","x,y,z"};
// flatMap
Arrays.stream(arr).flatMap(q -> {
String[] split = q.split(",");
// 把一个流拆分多个流然后又合并为一个流
Stream<String> stream = Arrays.stream(split);
return stream;
}).forEach(System.out::println);
}
(8) peek
:如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。
public static void main(String[] args) {
// 创建流
User zs = new User("zs", 18);
User ls = new User("ls", 28);
List<User> userList = Arrays.asList(zs, ls);
userList.stream()
.peek(q -> q.setAge(22))
.forEach(System.out::println);
}
当然还有其他的一些操作,这里就不一一演示了
3、终止操作
(1)匹配、聚合操作
allMatch
:接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false
noneMatch
:接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false
anyMatch
:接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false
findFirst
:返回流中第一个元素
findAny
:返回流中的任意元素
count
:返回流中元素的总个数
max
:返回流中元素最大值
min
:返回流中元素最小值
public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(4, 5, 6, 2, 1, 2, 3, 5);
boolean allMatch = asList.stream().allMatch(q -> q > 0);
System.out.println("allMatch = " + allMatch);
boolean noneMatch = asList.stream().noneMatch(q -> q < 0);
System.out.println("noneMatch = " + noneMatch);
boolean anyMatch = asList.stream().anyMatch(q -> q % 2 == 0);
System.out.println("anyMatch = " + anyMatch);
Integer findFirst = asList.stream().findFirst().get();
System.out.println("findFirst = " + findFirst);
Integer findAny = asList.stream().findAny().get();
System.out.println("findAny = " + findAny);
// long count = asList.stream().count();
long count = asList.size();
System.out.println("count = " + count);
Integer max = asList.stream().max(Comparator.comparingInt(o -> o)).get();
System.out.println("max = " + max);
Integer min = asList.stream().min(Integer::compareTo).get();
System.out.println("min = " + min);
}
(2) 规并操作
Optional<T> reduce(BinaryOperator<T> accumulator)
:第一次执行时,accumulator函数的第一个参数为流中的第一个元素,第二个参数为流中元素的第二个元素;第二次执行时,第一个参数为第一次函数执行的结果,第二个参数为流中的第三个元素;依次类推。
T reduce(T identity, BinaryOperator<T> accumulator)
:流程跟上面一样,只是第一次执行时,accumulator函数的第一个参数为identity,而第二个参数为流中的第一个元素。
<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner)
:在串行流(stream)中,该方法跟第二个方法一样,即第三个参数combiner不会起作用。在并行流(parallelStream)中,我们知道流被fork join出多个线程进行执行,此时每个线程的执行流程就跟第二个方法reduce(identity,accumulator)一样,而第三个参数combiner函数,则是将每个线程的执行结果当成一个新的流,然后使用第一个方法reduce(accumulator)流程进行规约。
public static void main(String[] args) {
// 创建流
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5);
Integer one = asList.stream().reduce(Integer::sum).get();
System.out.println("one = " + one);
Integer two = asList.stream().reduce(100, Integer::sum);
System.out.println("two = " + two);
Integer three = asList.parallelStream().reduce(100,
Integer::sum,
(x, y) -> x * y);
System.out.println("three = " + three);
}
(3) 收集操作
collect
:接收一个Collector实例,将流转化为其他形式,常用的List、Set、Map、Collection。
- 内部通过Collectors这个类进行相应的操作
(4) Collectors相关操作
toCollection toList() toSet() toMap
: 将输入元素累积到一个集合中
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.replaceAll(q -> q > 5 ? q + 10 : q);
System.out.println("list = " + list);
list.sort((o1, o2) -> o1 - o2);
// 转Collection
Collection<Integer> collection = list.parallelStream().collect(Collectors.toCollection(HashSet::new));
// 转List
List<Integer> integerList = list.parallelStream().collect(Collectors.toList());
// 转Set
Set<Integer> set = list.parallelStream().collect(Collectors.toSet());
// 转Map
Map<Integer, Integer> map = list.parallelStream().collect(Collectors.toMap(item -> item, integer -> integer));
}
joining
: 连接字符串
// joining
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f", "g");
String result = list.parallelStream().collect(Collectors.joining(",", "[", "]"));
System.out.println("result = " + result);
mapping/flatMapping
: 它将Function应用于输入元素,然后将它们累积到给定的Collector
Set<String> setStr = Stream.of("a", "a", "b")
.collect(Collectors.mapping(String::toUpperCase, Collectors.toSet()));
System.out.println(setStr); // [A, B]
Set<String> setStr1 = Stream.of("a", "a", "b")
.collect(Collectors.flatMapping(s -> Stream.of(s.toUpperCase()), Collectors.toSet()));
System.out.println(setStr1); // [A, B]
collectingAndThen
: 返回一个收集器,该收集器将输入元素累积到给定的收集器中,然后执行其他完成功能
List<String> strList2 = Lists.newArrayList("1", "2", "10", "100", "20", "999");
List<String> unmodifiableList = strList2.parallelStream()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
System.out.println(unmodifiableList); // [1, 2, 10, 100, 20, 999]
counting
: 计数
Long evenCount = Stream.of(1, 2, 3, 4, 5).filter(x -> x % 2 == 0).collect(Collectors.counting());
System.out.println(evenCount); // 2
minBy
: 根据给定的比较器返回最小元素
Optional<Integer> min = Stream.of(1, 2, 3, 4, 5).collect(Collectors.minBy((x, y) -> x - y));
System.out.println(min); // Optional[1]
maxBy
: 它根据给定的比较器返回最大元素
Optional<Integer> max = Stream.of(1, 2, 3, 4, 5).collect(Collectors.maxBy((x, y) -> x - y));
System.out.println(max); // Optional[5]
summingInt/summingLong/summingDouble
: 求总和
List<String> strList3 = Arrays.asList("1", "2", "3", "4", "5");
Integer sum = strList3.parallelStream().collect(Collectors.summingInt(Integer::parseInt));
System.out.println(sum); // 15
Long sumL = Stream.of("12", "23").collect(Collectors.summingLong(Long::parseLong));
System.out.println(sumL); // 35
Double sumD = Stream.of("1e2", "2e3").collect(Collectors.summingDouble(Double::parseDouble));
System.out.println(sumD); // 2100.0
averagingInt/averagingLong/averagingDouble
: 求平均值
List<String> strList4 = Arrays.asList("1", "2", "3", "4", "5");
Double average = strList4.parallelStream().collect(Collectors.averagingInt(Integer::parseInt));
System.out.println(average); // 3.0
Double averageL = Stream.of("12", "23").collect(Collectors.averagingLong(Long::parseLong));
System.out.println(averageL); // 17.5
Double averageD = Stream.of("1e2", "2e3").collect(Collectors.averagingDouble(Double::parseDouble));
System.out.println(averageD); // 1050.0
groupingBy
: 分组
Map<Integer, List<Integer>> mapGroupBy = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.groupingBy(x -> x * 10));
System.out.println(mapGroupBy); // {50=[5], 20=[2], 40=[4, 4], 10=[1], 30=[3, 3]}
groupingByConcurrent
: 分组,是并发和无序的
Map<Integer, List<Integer>> mapGroupBy = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.groupingByConcurrent(x -> x * 10));
System.out.println(mapGroupBy); // {50=[5], 20=[2], 40=[4, 4], 10=[1], 30=[3, 3]}
partitioningBy
: 返回一个Collector,它根据Predicate对输入元素进行分区,并将它们组织成Map <Boolean,List >
Map<Boolean, List<Integer>> mapPartitionBy = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.partitioningBy(x -> x % 2 == 0));
System.out.println(mapPartitionBy); // {false=[1, 3, 5, 3], true=[2, 4, 4]}
BinaryOperator
: 返回一个收集器,它在指定的BinaryOperator下执行其输入元素的减少。这主要用于多级缩减,例如使用groupingBy()和partitioningBy()方法指定下游收集器
Map<Boolean, Optional<Integer>> reducing = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.partitioningBy(
x -> x % 2 == 0, Collectors.reducing(BinaryOperator.maxBy(Comparator.comparing(Integer::intValue)))));
System.out.println(reducing); // {false=Optional[5], true=Optional[4]}
summarizingInt
: 返回统计数据:min, max, average, count, sum
IntSummaryStatistics summarizingInt = Stream.of("12", "23", "35")
.collect(Collectors.summarizingInt(Integer::parseInt));
System.out.println(summarizingInt);
//IntSummaryStatistics{count=3, sum=70, min=12, average=23.333333, max=35}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
上一篇:java后端分片上传接口
下一篇:java的数据类型分为两大类