23 KiB
23 KiB
Java Stream详解
创建Stream
Stream.builder()创建
Stream<Integer> build = Stream.<Integer>builder()
.add(1)
.add(12)
.add(3)
.add(34)
.build();
Stream.of创建
Stream<Integer> integerStream = Stream.of(1, 2, 34, 5);
空Stream创建
Stream<Object> objectStream = Stream.empty();
Stream.generate创建
如果不加限制运行时会一直创建像死循环一样
// 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创建创建
// IntStream创建[1,10)
IntStream.range(1, 10)
.forEach(System.out::println);
IntStream.rangeClosed创建闭区间
// 创建闭区间[1,10]
IntStream.rangeClosed(1,10)
.forEach(System.out::println);
Arrays.asList创建
// Arrays.asList创建
Arrays.asList("a","b","c","d","e","f")
.forEach(System.out::println);
创建Stream<Map.Entry<String, String>>
// 创建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
// Files中的Stream
Stream<String> lines = Files.lines(Paths.get("xxx.md"), StandardCharsets.UTF_8);
Stream的操作
distinct操作
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操作
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操作
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操作
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操作
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修改了其中的年龄,那么这个值会被改变
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操作
排序操作,也可以指定内容进行排序
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中也有这个
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操作
// 需要满足所有元素都匹配条件
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操作
// 找到第一个数字
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那么后面就无法再跟其它流函数
计数、求和、最小值、最大值
// 计数
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
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> upperCaseNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
toSet
将元素输出到 Set
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Set<String> uniqueNames = names.stream()
.collect(Collectors.toSet());
toMap
将元素输出到 Map
- 2个参数:key,value
- 3个参数:key,value,处理key冲突问题
- 4个参数:key,value,处理key冲突问题,转换map类型
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Map<String, Integer> nameLengthMap = names.stream()
.collect(Collectors.toMap(name -> name, String::length));
reduce
语法
Optional<T> reduce(BinaryOperator<T> accumulator)
Optional<T> reduce(T identity, BinaryOperator<T> accumulator)
使用
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
语法
static Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper)
使用
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类型
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 + ")";
}
}
}
输出:
{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
求平均值
// 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
先计算平均年龄,之后将计算结果转为整数,可以理解为:先收集之后再干嘛
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类似
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,先操作(此操作会可以改变其类似),之后在做处理
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个参数:将元素连接,传入第一个参数进行分割,第二个参数是整个处理完成元素的前缀,第三个参数是整个处理完成的后缀
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
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
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
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
求最小值
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
求最大值
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
求和转成类型
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
求和转成类型
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
求和转成类型
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集合
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;
}
}
}