MultiThread/README/Java Stream详解.md

967 lines
23 KiB
Markdown
Raw Permalink Normal View History

2025-01-21 13:44:35 +08:00
# Java Stream详解
## 创建Stream
### Stream.builder()创建
```java
Stream<Integer> build = Stream.<Integer>builder()
.add(1)
.add(12)
.add(3)
.add(34)
.build();
```
### Stream.of创建
```java
Stream<Integer> integerStream = Stream.of(1, 2, 34, 5);
```
### 空Stream创建
```java
Stream<Object> objectStream = Stream.empty();
```
### Stream.generate创建
如果不加限制运行时会一直创建像死循环一样
```java
// Stream.generate创建
Stream<Integer> generate = Stream.generate(() -> ThreadLocalRandom.current().nextInt(10))
.limit(10);
```
### Stream.iterate创建
```
// 不加限制会一直创建
Stream.iterate(100, seed -> seed + 1)
.limit(10)
.forEach(System.out::println);
```
### IntStream创建创建
```java
// IntStream创建[1,10)
IntStream.range(1, 10)
.forEach(System.out::println);
```
### IntStream.rangeClosed创建闭区间
```java
// 创建闭区间[1,10]
IntStream.rangeClosed(1,10)
.forEach(System.out::println);
```
### Arrays.asList创建
```java
// Arrays.asList创建
Arrays.asList("a","b","c","d","e","f")
.forEach(System.out::println);
```
### 创建Stream<Map.Entry<String, String>>
```java
// 创建Stream<Map.Entry<String, String>>
Stream<Map.Entry<String, String>> stream = new HashMap<String, String>() {{
put("a", "b");
put("c", "d");
}}.entrySet().stream();
```
### Files中的Stream
```java
// Files中的Stream
Stream<String> lines = Files.lines(Paths.get("xxx.md"), StandardCharsets.UTF_8);
```
## Stream的操作
### distinct操作
```java
Stream<Object> stream = new ArrayList<>() {{
add(1);
add(2);
add(2);
add(3);
add(3);
add(4);
}}.stream();
// 去重操作
stream.distinct().forEach(System.out::println);
```
> 输出:
>
> ```
> 1
> 2
> 3
> 4
> ```
### filter操作
```java
stream = new ArrayList<>() {{
add(1);
add(2);
add(2);
add(3);
add(3);
add(4);
}}.stream();
// 过滤器满足值为2的筛选
stream.filter(x -> x.equals(2)).forEach(System.out::println);
```
### limit操作
```java
stream = new ArrayList<>() {{
add(1);
add(2);
add(2);
add(3);
add(3);
add(4);
}}.stream();
// 选择序列个数为3
stream.limit(3).forEach(System.out::println);
```
### map操作
```java
stream = new ArrayList<>() {{
add(1);
add(2);
add(2);
add(3);
add(3);
add(4);
}}.stream();
// 映射,可以修改原本的类型
stream.map(Object::toString).forEach(System.out::println);
```
### skip操作
```java
stream = new ArrayList<>() {{
add(1);
add(2);
add(2);
add(3);
add(3);
add(4);
}}.stream();
// 跳过前两个数
stream.skip(2).forEach(System.out::println);
```
### peek操作
如果对一个对象进行操作比如Person中有姓名和年龄这时候通过peek修改了其中的年龄那么这个值会被改变
```java
stream = new ArrayList<>() {{
add(1);
add(2);
add(2);
add(3);
add(3);
add(4);
}}.stream();
// 不会使元素数据、类型产生改变
stream.peek(x -> ThreadLocalRandom.current().nextInt(100)).limit(10).forEach(System.out::println);
```
### sorted操作
排序操作,也可以指定内容进行排序
```java
stream = new ArrayList<>() {{
add(1);
add(2);
add(2);
add(3);
add(3);
add(4);
}}.stream();
// 从小到大排序
stream.sorted().forEach(System.out::println);
// 提供重载方法
stream.sorted(Comparator.comparing(Object::toString)).forEach(System.out::println);
```
### flatMap操作
扁平化数据JavaScript中也有这个
```java
ArrayList<Integer> list = new ArrayList<>() {{
add(1);
add(2);
add(2);
add(3);
add(3);
add(4);
}};
List<ArrayList<Integer>> arrayListList = List.of(list);
// 扁平化数组
arrayListList.stream().flatMap(Collection::stream).forEach(System.out::println);
```
### match操作
```java
// 需要满足所有元素都匹配条件
boolean allMatch = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
.allMatch(i -> i > 4);
System.out.println(allMatch);// false
// 只要有一个元素满足匹配条件
boolean anyMatch = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
.anyMatch(x -> x > 4);
System.out.println(anyMatch);// true
// 所有元素都不满足条件
boolean noneMatch = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
.noneMatch(x -> x > 4);
System.out.println(noneMatch);// false
```
### find操作
```java
// 找到第一个数字
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
.findFirst()
.ifPresent(System.out::println);
// 获取任意一个数字
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
.findAny()
.ifPresent(System.out::println);
```
### forEach操作
不解释放在最后如果使用了forEach那么后面就无法再跟其它流函数
### 计数、求和、最小值、最大值
```java
// 计数
long count = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
.count();
System.out.println(count);// 9
// 求和
long sum = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
.mapToLong(Integer::longValue)
.sum();
System.out.println(sum);
// 查找最小值
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
.min(Comparator.comparing(i -> i))
.ifPresent(System.out::println);
// 查找最大值
Optional<Integer> max = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
.max(Comparator.comparing(i -> i));
System.out.println(max.get());
```
## Collectors使用
收集器
### toList
将元素输出到 list
```java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> upperCaseNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
```
### toSet
将元素输出到 Set
```java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Set<String> uniqueNames = names.stream()
.collect(Collectors.toSet());
```
### toMap
将元素输出到 Map
- 2个参数keyvalue
- 3个参数keyvalue处理key冲突问题
- 4个参数keyvalue处理key冲突问题转换map类型
```java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Map<String, Integer> nameLengthMap = names.stream()
.collect(Collectors.toMap(name -> name, String::length));
```
### reduce
语法
```java
Optional<T> reduce(BinaryOperator<T> accumulator)
Optional<T> reduce(T identity, BinaryOperator<T> accumulator)
```
使用
```java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 使用 reduce 求和
Optional<Integer> sum = numbers.stream()
.reduce(Integer::sum);
sum.ifPresent(System.out::println); // 输出: 15
// 使用带初始值的 reduce
int sumWithIdentity = numbers.stream()
.reduce(0, Integer::sum);
System.out.println(sumWithIdentity); // 输出: 15
```
### summingDouble
将求和后的结果转成Double
语法
```java
static Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper)
```
使用
```java
public class StreamExample07 {
public static void main(String[] args) {
List<Product> products = Arrays.asList(
new Product("Apple", 1.20),
new Product("Banana", 0.80),
new Product("Orange", 1.00)
);
double totalCost = products.stream().mapToDouble(Product::getPrice).sum();
System.out.println("Total Cost: " + totalCost); // 输出: Total Cost: 3.0
}
@Getter
private static class Product {
private final String name;
private final double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
}
}
```
### groupingBy
- 1个参数指定key是什么
- 2个参数指定key和value
- 3个参数key,value,value类型
```java
public class StreamExample08 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 30),
new Person("David", 25)
);
// 根据年龄将一组人分组
Map<Integer, List<Person>> groupedByAge = people.stream()
.collect(Collectors.groupingBy(Person::getAge));
// 自定义收集器:可以传递第二个参数来指定下游收集器。
Map<Integer, Long> groupedByAgeCount = people.stream()
.collect(Collectors.groupingBy(Person::getAge, Collectors.counting()));
// 多级分组:可以嵌套使用 groupingBy 进行多级分组。
Map<Integer, Map<String, List<Person>>> groupedByAgeAndName = people.stream()
.collect(Collectors.groupingBy(Person::getAge, Collectors.groupingBy(Person::getName)));
System.out.println(groupedByAge);
}
@Getter
static class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
}
```
> 输出:
>
> ```java
> {25=[Bob (25), David (25)], 30=[Alice (30), Charlie (30)]}
> {25=2, 30=2}
> {25={Bob=[Bob (25)], David=[David (25)]}, 30={Alice=[Alice (30)], Charlie=[Charlie (30)]}}
> ```
### Collectors.averaging
求平均值
```java
// averagingLong
List<Long> numbers = Arrays.asList(1L, 2L, 3L, 4L, 5L);
double averagingLongNumbers = numbers.stream()
.collect(Collectors.averagingLong(Long::longValue));
System.out.println("Average: " + averagingLongNumbers);
// averagingDouble
List<Double> averagingDoubleNumbers = Arrays.asList(1.5, 2.5, 3.5, 4.5, 5.5);
double averagingDouble = averagingDoubleNumbers.stream()
.collect(Collectors.averagingDouble(Double::doubleValue));
System.out.println("Average: " + averagingDouble);
// averagingInt
List<Integer> averagingIntNumbers = Arrays.asList(1, 2, 3, 4, 5);
double averagingInt = averagingIntNumbers.stream()
.collect(Collectors.averagingInt(Integer::intValue));
System.out.println("Average: " + averagingInt);
```
### Collectors.collectingAndThen
先计算平均年龄,之后将计算结果转为整数,可以理解为:先收集之后再干嘛
```java
public class StreamExample10 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35)
);
// 使用 Collectors.collectingAndThen 计算平均年龄并转换为整数
int averageAge = people.stream()
.collect(Collectors.collectingAndThen(
Collectors.averagingInt(Person::getAge),// 先计算平均年龄
Double::intValue // 之后将结果转换为整数
));
System.out.println("Average Age: " + averageAge);
}
@Getter
static class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
}
```
### Collectors.counting使用
求总数和SQL中count类似
```java
public class StreamExample11 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35)
);
// 使用 Collectors.counting 统计人数
long count = people.stream()
.collect(Collectors.counting());
System.out.println("Total number of people: " + count);
}
@Getter
static class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
}
```
### Collectors.mapping
类似Stream中的map先操作(此操作会可以改变其类似),之后在做处理
```java
public class StreamExample12 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35),
new Person("David", 40)
);
// 使用 Collectors.mapping 和 Collectors.toSet 只收集大于 30 岁的人的年龄
Set<Integer> agesAbove30 = people.stream()
.filter(person -> person.getAge() > 30)
.collect(Collectors.mapping(Person::getAge, Collectors.toSet()));
System.out.println("Ages above 30: " + agesAbove30);
}
@Getter
static class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
}
```
### Collectors.joining
- 无参数:将元素连接在一起,中间没有内容分隔
- 1个参数将元素连接使用传入的符号进行分割
- 3个参数将元素连接传入第一个参数进行分割第二个参数是整个处理完成元素的前缀第三个参数是整个处理完成的后缀
```java
public class StreamExample13 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice"),
new Person("Bob"),
new Person("Charlie")
);
// 使用 Collectors.joining 连接名字,添加前缀和后缀
String result = people.stream()
.map(Person::getName) // 提取名字
.collect(Collectors.joining(", ", "[", "]")); // 使用逗号和空格作为分隔符,添加前缀和后缀
System.out.println("Names: " + result);// Names: [Alice, Bob, Charlie]
}
@Getter
static class Person {
private final String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
}
```
### Collectors.summing使用
#### summingInt
求和转成int
```java
public class StreamExample14 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35)
);
// 使用 Collectors.summingInt 计算年龄总和
int totalAge = people.stream()
.collect(Collectors.summingInt(Person::getAge));
System.out.println("Total Age: " + totalAge);
}
@Getter
static class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
}
```
#### summingDouble
求和转成double
```java
public class StreamExample15 {
public static void main(String[] args) {
List<Product> products = Arrays.asList(
new Product("Laptop", 999.99),
new Product("Smartphone", 499.99),
new Product("Tablet", 299.99)
);
// 使用 Collectors.summingDouble 计算价格总和
double totalPrice = products.stream()
.collect(Collectors.summingDouble(Product::getPrice));
System.out.println("Total Price: " + totalPrice);
}
@Getter
static
class Product {
private final String name;
@Getter
private final double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
}
}
```
#### summingLong
求和转成long
```java
public class StreamExample16 {
public static void main(String[] args) {
List<Transaction> transactions = Arrays.asList(
new Transaction(1000L),
new Transaction(2500L),
new Transaction(1500L)
);
// 使用 Collectors.summingLong 计算总金额
long totalAmount = transactions.stream()
.collect(Collectors.summingLong(Transaction::getAmount));
System.out.println("Total Amount: " + totalAmount);
}
@Getter
static class Transaction {
private final long amount;
public Transaction(long l) {
this.amount = l;
}
}
}
```
### Collectors.minBy和Collectors.maxBy
#### minBy
求最小值
```java
public class StreamExample17 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35)
);
// 使用 Collectors.minBy 找到年龄最小的人
Optional<Person> youngest = people.stream()
.collect(Collectors.minBy(Comparator.comparingInt(Person::getAge)));
youngest.ifPresent(person ->
System.out.println("Youngest Person: " + person.getName() + ", Age: " + person.getAge()));
}
@Getter
static class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
}
```
#### maxBy
求最大值
```java
public class StreamExample18 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35)
);
// 使用 Collectors.maxBy 找到年龄最大的人
Optional<Person> oldest = people.stream()
.collect(Collectors.maxBy(Comparator.comparingInt(Person::getAge)));
oldest.ifPresent(person ->
System.out.println("Oldest Person: " + person.getName() + ", Age: " + person.getAge()));
}
@Getter
static class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
}
```
### Collectors.summarizing
#### Collectors.summarizingInt
求和转成类型
```java
public class StreamExample19 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35)
);
// 使用 Collectors.summarizingInt 统计年龄信息
IntSummaryStatistics ageStats = people.stream()
.collect(Collectors.summarizingInt(Person::getAge));
System.out.println("Count: " + ageStats.getCount());
System.out.println("Sum: " + ageStats.getSum());
System.out.println("Min: " + ageStats.getMin());
System.out.println("Max: " + ageStats.getMax());
System.out.println("Average: " + ageStats.getAverage());
}
@Getter
static class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
}
```
#### Collectors.summarizingLong
求和转成类型
```java
public class StreamExample20 {
public static void main(String[] args) {
List<Transaction> transactions = Arrays.asList(
new Transaction(1000L),
new Transaction(2500L),
new Transaction(1500L)
);
// 使用 Collectors.summarizingLong 统计金额信息
LongSummaryStatistics amountStats = transactions.stream()
.collect(Collectors.summarizingLong(Transaction::getAmount));
System.out.println("Count: " + amountStats.getCount());
System.out.println("Sum: " + amountStats.getSum());
System.out.println("Min: " + amountStats.getMin());
System.out.println("Max: " + amountStats.getMax());
System.out.println("Average: " + amountStats.getAverage());
}
@Getter
static class Transaction {
private final long amount;
public Transaction(long amount) {
this.amount = amount;
}
}
}
```
#### Collectors.summarizingDouble
求和转成类型
```java
public class StreamExample21 {
public static void main(String[] args) {
List<Product> products = Arrays.asList(
new Product("Laptop", 1200.50),
new Product("Phone", 800.75),
new Product("Tablet", 300.00)
);
// 使用 Collectors.summarizingDouble 统计价格信息
DoubleSummaryStatistics priceStats = products.stream()
.collect(Collectors.summarizingDouble(Product::getPrice));
System.out.println("Count: " + priceStats.getCount());
System.out.println("Sum: " + priceStats.getSum());
System.out.println("Min: " + priceStats.getMin());
System.out.println("Max: " + priceStats.getMax());
System.out.println("Average: " + priceStats.getAverage());
}
@Getter
static
class Product {
private final String name;
private final double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
}
}
```
### Collectors.partitioningBy
以Boolean为 key的分组key为Boolean值后面是value值属于Map集合
```java
public class StreamExample22 {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 17),
new Person("Charlie", 25),
new Person("David", 15)
);
// 使用 Collectors.partitioningBy 按年龄分组
Map<Boolean, List<Person>> partitionedByAge = people.stream()
.collect(Collectors.partitioningBy(person -> person.getAge() >= 18));
// 输出结果
System.out.println("成年人:");
partitionedByAge.get(true).forEach(person -> System.out.println(person.getName()));
System.out.println("未成年人:");
partitionedByAge.get(false).forEach(person -> System.out.println(person.getName()));
}
@Getter
static class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
}
```