什么是java的Stream流?
它是java处理集合的一种新方式。它允许我们处理集合中的元素,将其转换或过滤,并返回结果.
我们可以很方便的用Stream进行处理集合。
在使用stream流的同时,很经常的会和lambda表达式配合使用
在刚刚接触到stream流的时候,我们肯定是需要知道如何用它,大体分为三大步骤
创建Stream
可以使用集合的stream()方法或Arrays.stream()方法创建Stream
中间操作
可以对Stream进行中间操作来过滤、转换或执行其他操作。常见的中间操作有filter()、map()、flatMap()、distinct()、sorted()和peek()等,后面将对其进行详细展开说明
终端操作
执行终端操作会触发Stream的处理,返回一个结果或发生一个副作用。常见的终端操作有forEach()、count()、reduce()、collect()、anyMatch()、allMatch()和noneMatch()等,后面将对其进行详细展开说明
filter(Predicate predicate)
过滤
该中间操作对Stream中的元素进行过滤操作,只将符合条件的元素留下来,返回一个由符合条件的元素组成的新Stream
map(Function Mapper)
转换
该中间操作对Stream中的元素进行转换操作,对每一个元素进行对应处理,返回一个新的Stream。
flatMap(Function mapper)
转换为Stream
该中间操作将Stream中的每一个元素转换为一个Stream,再把这些转换出的Stream合并成一个新的Stream返回
distinct()
去重
该中间操作去除Stream中重复的元素,返回一个没有重复元素的新Stream
sorted()
排序
该中间操作对Stream中的元素进行排序操作,返回一个排序后的新Stream。
peek(Consumer action)
消费操作
该中间操作在Stream中的每一个元素执行消费操作,返回一个仍是原来的Stream。
limit(long maxSize)
截取数据
该中间操作截取Stream中前maxSize个元素,返回一个新的Stream。
skip(long n)
跳过元素
该中间操作跳过Stream中前n个元素,返回一个新的Stream。
需要注意的是,这些Stream中间操作可以任意串联,形成一条Stream流水线,每一个中间操作都会返回一个新的Stream,而不会改变原Stream中的元素。在使用Stream时,需要注意Stream流的特殊性质:它们只能被“消费”一次。如果需要对Stream中的数据进行多次操作,需要重新生成一个新的Stream对象。
forEach()
迭代操作
该终端操作对 Stream 中的每个元素进行迭代操作,并调用指定的操作来处理每个元素
count()
返回数量
该终端操作将并行的Stream转换为一个普通的Stream,可进行单线程处理操作。
reduce()
累加
该终端操作将 Stream 中的元素通过指定操作累加起来,返回计算结果。
collect()
转集合或数组
该终端操作将 Stream 中的元素转换成一个集合或一个值,返回集合或值。
max()
取最大元素
该终端操作取 Stream 中的最大元素。
min()
取最小元素
该终端操作取 Stream 中的最小元素。
allMatch()
是否满足条件
该终端操作检查 Stream 中的所有元素是否都满足指定的条件。
anyMatch()
任一满足条件
该终端操作检查 Stream 中是否有任何一个元素满足指定的条件。
noneMatch()
无一满足条件
该终端操作检查 Stream 中是否没有任何一个元素满足指定的条件。
特殊终端操作: 除了以上的终端操作,还有这些特殊终端操作:findFirst()
、findAny()
、toArray()
这里将介绍如何使用中间操作并用实例演示
例子:
// 转换集合
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Ella");
// 过滤拿取长度大于4的数据
List<String> longNames = names.stream()
.filter(name -> name.length() > 4)
.collect(Collectors.toList());
// 打印结果
System.out.println(longNames);
结果:
[Alice, Charlie, David]
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
//将 Stream 中原有的整数元素转换为它们的平方数,最终将转换后的元素收集到一个新的 List 中。
List<Integer> squares = numbers.stream()
.map(num -> num * num)
.collect(Collectors.toList());
打印结果
System.out.println(squares);
结果:
[1, 4, 9, 16, 25, 36, 49, 64, 81]
例子:
// 转换嵌套了多个 List 的 List
List<List<String>> nestedList = Arrays.asList(
Arrays.asList("apple", "banana", "orange"),
Arrays.asList("cat", "dog", "bird"),
Arrays.asList("Java", "Kotlin", "Python")
);
// 使用 flatMap() 方法将嵌套了多个 List 的 List 转换为一个扁平化的 Stream,
//然后使用 collect() 方法将转换后的所有元素收集到一个新的 List 中。
List<String> flatList = nestedList.stream()
.flatMap(list -> list.stream())
.collect(Collectors.toList());
// 打印结果
System.out.println(flatList);
结果:
[apple, banana, orange, cat, dog, bird, Java, Kotlin, Python]
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 4, 5, 5, 6, 3, 7, 8, 9, 9);
// 使用 distinct() 方法将 Stream 中的重复元素去除,然后使用 collect() 方法将所有的不同元素收集到一个新的 List 中
List<Integer> uniqueNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList());
// 打印结果
System.out.println(uniqueNumbers);
结果:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
例子:
// 转换集合
List<String> names = Arrays.asList("Alice", "bob", "Charlie", "david", "Ella");
// 按照字母顺序排序
List<String> sortedNames = names.stream()
.sorted()
.collect(Collectors.toList());
// 打印结果
System.out.println(sortedNames);
结果:
[Alice, Charlie, Ella, bob, david]
若想按照自定义规则进行排序,可以在 sorted() 方法中传入一个自定义的 Comparator。以下为带Comparator的例子
例子:
// 转换集合
List<String> names = Arrays.asList("Alice", "bob", "Charlie", "david", "Ella");
// 定义自定义Comparator
Comparator<String> lengthComparator = (str1, str2) -> Integer.compare(str1.length(), str2.length());
// 按照字母长度排序
List<String> sortedNames = names.stream()
.sorted(lengthComparator)
.collect(Collectors.toList());
// 打印结果
System.out.println(sortedNames);
结果:
[bob, Ella, Alice, david, Charlie]
例子:
// 转换集合
List<String> names = Arrays.asList("Alice", "bob", "Charlie", "david", "Ella");
// 使用 peek() 方法在 Stream 中打印每个元素的原始名称和名称转换为大写后的名称。
//在执行完 peek() 方法后,Stream 仍然保持不变,我们可以继续对 Stream 进行其他操作,
//例如使用 map() 方法将名称转换为大写字母,并将所有元素收集到一个新的 List 对象中
List<String> resultNames = names.stream()
.peek(name -> System.out.println("原始值: " + name))
.map(name -> name.toUpperCase())
.peek(name -> System.out.println("处理值: " + name))
.collect(Collectors.toList());
ps: 该stream执行完,names 和resultNames 的值是一样的
结果:
原始值: Alice
处理值: ALICE
原始值: bob
处理值: BOB
原始值: Charlie
处理值: CHARLIE
原始值: david
处理值: DAVID
原始值: Ella
处理值: ELLA
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 获取前三条数据
List<Integer> limitedNumbers = numbers.stream()
.limit(3)
.collect(Collectors.toList());
// 打印结果
System.out.println(limitedNumbers);
结果:
[1, 2, 3]
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 跳过前2个元素
List<Integer> resultNumbers = numbers.stream()
.skip(2)
.collect(Collectors.toList());
// 打印结果
System.out.println(resultNumbers);
结果:
[3, 4, 5]
这里将介绍如何使用终端操作并用实例演示,注意由于是终端操作,
使用该操作处理完数据之后stream无法再使用
例子:
// 转换集合
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Ella");
// 打印大写字符
names.stream()
.forEach(name -> System.out.println("Hello, " + name.toUpperCase() + "!"));
结果:
Hello, ALICE!
Hello, BOB!
Hello, CHARLIE!
Hello, DAVID!
Hello, ELLA!
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 计算长度
long count = numbers.stream()
.count();
// 打印结果
System.out.println("长度为: " + count);
结果:
长度为:5
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 求和,需要两个参数,初始值和 BinaryOperator 对象
// 本实例用的sum()方法
int sum = numbers.stream()
.reduce(0, Integer::sum);
System.out.println("求和: " + sum);
结果:
求和:15
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(10, 20, 30, 40, 50);
// 求最大值
Optional<Integer> max = numbers.stream()
.max(Integer::compareTo);
// 判空
if (max.isPresent()) {
System.out.println("最大值: " + max.get());
} else {
System.out.println("空值");
}
结果:
最大值:50
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(10, 20, 30, 40, 50);
// 求最大值
Optional<Integer> min= numbers.stream()
.min(Integer::compareTo);
// 判空
if (max.isPresent()) {
System.out.println("最小值: " + min.get());
} else {
System.out.println("空值");
}
结果:
最小值:10
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 判断所有元素是否都大于0
boolean allGreaterThanZero = numbers.stream()
.allMatch(n -> n > 0);
System.out.println("所有元素是否都大于0: " + allGreaterThanZero);
结果:
所有元素是否都大于0:true
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 判断是否有任一元素为偶数
boolean hasEvenNumber = numbers.stream()
.anyMatch(n -> n % 2 == 0);
// 打印结果
System.out.println("是否有任一元素为偶数: " + hasEvenNumber);
结果:
是否有任一元素为偶数:true
例子:
// 转换集合
List<String> fruits = Arrays.asList("apple", "banana", "pear", "orange");
// 判断元素都不包含字母a
boolean noneContainsA = fruits.stream()
.noneMatch(fruit -> fruit.contains("a"));
System.out.println("元素都不包含字母a: " + noneContainsA);
结果:
元素都不包含字母a:false
该终端操作为将处理的数据转为集合,以下为不同集合处理实例
转List例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 转List
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
// 打印结果
System.out.println(evenNumbers);
结果:
[2, 4]
转Set例子:
// 转换集合
List<String> fruits = Arrays.asList("apple", "banana", "pear", "banana", "orange");
// 转Set
Set<String> fruitSet = fruits.stream()
.collect(Collectors.toSet());
// 打印结果
System.out.println(fruitSet);
结果:
[banana, apple, pear, orange]
转Map例子:
// 转换集合
List<Person> persons = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 35),
new Person("David", 40)
);
// 转Map
Map<String, Integer> nameToAgeMap = persons.stream()
.collect(Collectors.toMap(Person::getName, Person::getAge));
System.out.println(nameToAgeMap);
结果:
{Alice=25, Bob=30, Charlie=35, David=40}
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 查找第一个偶数
Optional<Integer> firstEvenNumber = numbers.stream()
.filter(n -> n % 2 == 0)
.findFirst();
// 打印结果
if (firstEvenNumber.isPresent()) {
System.out.println("第一个偶数为: " + firstEvenNumber.get());
} else {
System.out.println("空值");
}
结果:
第一个偶数为:2
例子:
// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 查找任一一个偶数
Optional<Integer> anyEvenNumber = numbers.stream()
.filter(n -> n % 2 == 0)
.findAny();
// 打印结果
if (anyEvenNumber.isPresent()) {
System.out.println("任一偶数: " + anyEvenNumber.get());
} else {
System.out.println("空值");
}
结果:
任一偶数:2
例子:
// 转换集合
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 转Arrary
String[] namesArray = names.stream()
.toArray(String[]::new);
// 打印结果
System.out.println(Arrays.toString(namesArray));
结果:
[Alice, Bob, Charlie]
以下实例为我工作过程中比较常用的一些Stream处理实例,可供大家参考,不定时更新
例子:
// 转换集合
List<Person> persons = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 35),
new Person("David", 40)
);
// 获取名称
List<String> names = persons.stream()
.map(Person::getName)
.distinct()
.collect(Collectors.toList());
// 打印结果
System.out.println(names);
结果:
[Alice, Bob, Charlie, David]
例子:
// 转换集合
List<Person> persons = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 35),
new Person("David", 40),
new Person("Alice", 45)
);
// 根据名称分组
Map<String, List<Person>> personsByName = persons.stream()
.collect(Collectors.groupingBy(Person::getName));
// 打印结果
System.out.println(personsByName);
结果:
{
Alice=[Person{name='Alice', age=25}, Person{name='Alice', age=45}],
Bob=[Person{name='Bob', age=30}],
Charlie=[Person{name='Charlie', age=35}],
David=[Person{name='David', age=40}]
}
例子:
// 转换集合
List<Person> persons = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 35),
new Person("David", 40),
new Person("Alice", 45)
);
// 根据年龄排序
List<Person> sortedPersons = persons.stream()
.sorted(Comparator.comparing(Person::getAge))
.collect(Collectors.toList());
// 打印结果
System.out.println(sortedPersons);
结果:
[Person{name='Alice', age=25}, Person{name='Bob', age=30}, Person{name='Charlie', age=35}, Person{name='David', age=40}, Person{name='Alice', age=45}]
将两个 List 转换为 Stream,使用 flatMap 将两个 Stream 合并。
使用 filter 方法过滤其中一个字段属性一模一样的数据。可以使用 equals 方法进行比较,或者使用自定义的比较器。
如果存在匹配的数据,使用 findFirst 方法获取第一个匹配的元素。
例子:
Optional<Object1> result = list1.stream()
.flatMap(o1 -> list2.stream()
.filter(o2 -> o2.getField().equals(o1.getField()))
.map(o2 -> o1))
.findFirst();
其中,getField() 是一个方法,用于获取对象中的某个属性。Object1 和 Object2
分别代表两个类的类型,需要替换成你自己定义的类名和属性名。返回值使用 Optional 类型,因为可能存在没有匹配项的情况。
例子:
// 有对象person
public class Person {
// 姓名
private String name;
// 年龄
private Integer age;
}
List<Person> persons = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
);
// 转map
Map<String, Integer> personMap= persons.stream().collect(
Collectors.toMap(Person::getName, Person::getAge));
// 打印结果
System.out.println(personMap);
结果:
{Alice=25,Bob=30}
例子:
public class Person {
// 姓名
private String name;
// 年龄
private Integer age;
}
List<Person> persons = Arrays.asList(
new Person("Alice", 45),
new Person("Bob", 30),
new Person("Charlie", 35),
new Person("David", 40),
new Person("Alice", 45)
);
List<Person> samDataList = dataList.stream().collect(
Collectors.groupingBy(obj -> obj.getName() + obj.getAge()))
.values().stream()
.filter(group -> group.size() > 1)
.flatMap(List::stream)
.collect(Collectors.toList());
结果:
[Person{name='Alice', age=45},Person{name='Alice', age=45}]
以上就是JAVA 8的stream流的用法