Stream流
Stream的三个操作步骤
创建Stream
创建stream的四种方式
- 通过Collection系列集合提供的
stream()
方法或parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
Stream<String> stream2 = list.parallelStream();
Employee[] employees = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(employees);
Stream<String> stream3 = Stream.of("aa","bb","cc","dd");
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(10).forEach(System.out::println);
Stream.generate(()->Math.random()).forEach(System.out::println);
中间操作
中间操作:不会执行任何操作,终止操作:一次性执行全部内容,即“惰性求值”
1. 筛选与切片
方法 | 描述 |
---|
filter | 接收Lambda,从流中排除某些元素 |
limit | 截断流,使其元素不超过给定数量 |
skip(n) | 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补 |
distinct | 筛选,通过流所生成元素的hashCode() 和 equals() 去除重复元素 |
例子:
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode()
public class Employee {
private int id;
private String name;
private int age;
private double salary;
private Status status;
public enum Status {
BUSY,FREE,VOCATION;
}
public Employee(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
}
1.1 filter:过滤
List<Employee> employees = Arrays.asList(
new Employee(1, "张三", 18, 1111.11),
new Employee(2, "李四", 49, 2222.22),
new Employee(3, "赵六", 57, 3333.33),
new Employee(4, "田七", 35, 4444.44),
new Employee(4, "田七", 35, 4444.44)
);
@Test
public void test1() {
employees.stream()
.filter(e -> e.getAge() > 35)
.forEach(System.out::println);
Iterator<Employee> it = employees.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
1.2 limit:截取
package cn.luis.stream.intermediate;
import cn.luis.stream.Employee;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class LimitTest {
List<Employee> employees = Arrays.asList(
new Employee(1, "张三", 18, 1111.11),
new Employee(3, "赵六", 57, 3333.33),
new Employee(4, "田七", 35, 4444.44),
new Employee(2, "李四", 49, 2222.22),
new Employee(5, "田七", 35, 4444.44)
);
@Test
public void test2() {
employees.stream()
.filter(e -> {
return e.getAge() > 20;
})
.limit(2)
.forEach(System.out::println);
}
}
1.3 skip:跳过
package cn.luis.stream.intermediate.shanxuanqiepian;
import cn.luis.stream.common.Employee;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
public class SkipTest {
List<Employee> employees = Arrays.asList(
new Employee(1, "张三", 18, 1111.11),
new Employee(2, "李四", 49, 2222.22),
new Employee(3, "赵六", 57, 3333.33),
new Employee(4, "田七", 35, 4444.44),
new Employee(5, "田七", 35, 4444.44)
);
@Test
public void test3() {
employees.stream()
.filter(e -> e.getAge() > 18)
.skip(2)
.forEach(System.out::println);
}
}
1.4 distinct:去重
package cn.luis.stream.intermediate.shanxuanqiepian;
import cn.luis.stream.common.Employee;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
public class DistinctTest {
List<Employee> employees = Arrays.asList(
new Employee(1, "张三", 18, 1111.11),
new Employee(2, "李四", 49, 2222.22),
new Employee(3, "赵六", 57, 3333.33),
new Employee(4, "田七", 35, 4444.44),
new Employee(5, "田七", 35, 4444.44)
);
@Test
public void test4() {
employees.stream()
.filter(e -> {
return e.getAge() > 25;
})
.distinct()
.forEach(System.out::println);
}
}
2. 映射
map里传入Function函数型接口,传入一个参数返回一个值
方法 | 描述 |
---|
map | 接收lambda,将元素转换成其他形式或提取信息,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
flatMap | 接收一个函数作为参数,将该流中的每一个值都换成另一个流,然后把所有流连成一个流 |
例子:
package cn.luis.stream.intermediate.yingshe;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class MapTest {
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
@Test
public void test1() {
list.stream()
.map(s -> s.toUpperCase())
.forEach(System.out::println);
System.out.println("--------------------------");
Stream<Stream<Character>> stream = list.stream().map(MapTest::filterCharacter);
stream.forEach(sm -> {
sm.forEach(System.out::println);
});
}
@Test
public void test2() {
Stream<Character> characterStream = list.stream()
.flatMap(MapTest::filterCharacter);
characterStream.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str) {
List<Character> list = new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
}
3. 排序
方法 | 描述 |
---|
sorted() | 自然排序(Comparable) |
sorted(Comparator com) | 定制排序(Comparator) |
例子:
package cn.luis.stream.intermediate.sort;
import cn.luis.stream.common.Employee;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class SortedTest {
List<Employee> employees = Arrays.asList(
new Employee(1, "张三", 18, 1111.11),
new Employee(2, "李四", 49, 2222.22),
new Employee(3, "赵六", 57, 3333.33),
new Employee(4, "田七", 35, 4444.44),
new Employee(5, "田七", 35, 4444.44)
);
@Test
public void test1() {
Stream<Employee> sorted = employees.stream().sorted();
employees.stream()
.sorted((e1, e2) -> {
if (e1.getAge() == e2.getAge()) {
return e1.getName().compareTo(e2.getName());
} else {
Integer x = e1.getAge();
return x.compareTo(e2.getAge());
}
}).forEach(System.out::println);
}
}
终止操作
1. 查找与匹配
方法 | 描述 |
---|
allMatch | 检查是否匹配所有元素 |
anyMatch | 检查是否至少匹配一个元素 |
noneMatch | 检查是否没有匹配所有元素 |
findFirst | 返回第一个元素 |
findAny | 返回当前流中的任意元素 |
count | 返回流中元素的总个数 |
max | 返回流中的最大值 |
min | 返回流中的最小值 |
例子:
List<Employee> employees = Arrays.asList(
new Employee(1, "张三", 18, 1111.11, Status.BUSY),
new Employee(2, "李四", 49, 2222.22, Status.FREE),
new Employee(3, "赵六", 57, 3333.33, Status.BUSY),
new Employee(4, "田七", 35, 4444.44, Status.VOCATION),
new Employee(2, "李十四", 49, 2222.22, Status.FREE),
new Employee(2, "李十四", 49, 2222.22, Status.FREE),
new Employee(2, "李十四", 49, 2222.22, Status.FREE)
);
1.1 match:匹配
@Test
public void matchTest() {
boolean b = employees.stream()
.allMatch(e -> Employee.Status.BUSY.equals(e.getStatus()));
System.out.println(b);
boolean b2 = employees.stream()
.anyMatch(e -> Employee.Status.BUSY.equals(e.getStatus()));
System.out.println(b2);
boolean b3 = employees.stream()
.noneMatch(e -> Employee.Status.BUSY.equals(e.getStatus()));
System.out.println(b3);
}
1.2 find:查找
@Test
public void findTest() {
Optional<Employee> first = employees.stream()
.sorted(Comparator.comparingDouble(Employee::getSalary))
.findFirst();
System.out.println(first.get());
Optional<Employee> any = employees.stream()
.filter(e -> Employee.Status.FREE.equals(e.getStatus()))
.findAny();
System.out.println(any.get());
Optional<Employee> any2 = employees.parallelStream()
.filter(e -> Employee.Status.FREE.equals(e.getStatus()))
.findAny();
System.out.println(any2.get());
}
1.3 最值
@Test
public void numTest() {
long count = employees.stream()
.count();
System.out.println(count);
Optional<Employee> max = employees.stream()
.max(Comparator.comparingDouble(Employee::getAge));
System.out.println(max.get());
Optional<Double> min = employees.stream()
.map(Employee::getSalary)
.min(Double::compare);
System.out.println(min.get());
}
2. 规约
方法 | 描述 |
---|
reduce | 可以将流中的元素反复结合起来,得到一个值 |
public class EmpData {
public static List<Employee> findAllEmployee() {
return Arrays.asList(
new Employee(1, "张三", 18, 1111.11, Employee.Status.BUSY),
new Employee(2, "李四", 49, 2222.22, Employee.Status.FREE),
new Employee(3, "赵六", 57, 3333.33, Employee.Status.BUSY),
new Employee(4, "田七", 35, 4444.44, Employee.Status.VOCATION),
new Employee(2, "李十四", 49, 2222.22, Employee.Status.FREE),
new Employee(2, "李十四", 49, 2222.22, Employee.Status.FREE),
new Employee(2, "李十四", 49, 2222.22, Employee.Status.FREE)
);
}
}
public class ReduceTest {
List<Employee> employees = EmpData.findAllEmployee();
@Test
public void test3() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Integer a = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(a);
Integer b = list.stream()
.reduce(0, Integer::sum);
System.out.println(b);
Optional<Integer> c = list.stream()
.reduce(Integer::sum);
System.out.println(c.get());
Integer d = list.stream()
.reduce(Integer::sum).orElse(0);
System.out.println(d);
}
}
3. 收集
包括集合、计算、分组、分区
方法 | 描述 |
---|
collect | 将流转换为其他形式,接收一个Collectot接口的实现,用于给Stream中的元素汇总的方法 |
3.1 集合
方法 | 描述 |
---|
Collectors.toList() | 转成 List |
Collectors.toSet() | 转成 Set |
Collectors.toCollection(HashSet::new) | 放到其他类型集合 |
@Test
public void test4() {
List<String> nameList = employees.stream()
.map(Employee::getName)
.collect(Collectors.toList());
nameList.forEach(System.out::println);
System.out.println("-----------过滤重复数据--------------");
Set<String> nameSet = employees.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
nameSet.forEach(System.out::println);
System.out.println("-----------放到其他类型集合--------------");
HashSet<String> nameHashSet = employees.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new));
nameHashSet.forEach(System.out::println);
}
3.2 计算
方法 | 描述 |
---|
Collectors.counting() | 总数 |
Collectors.averagingDouble() | 平均值 |
Collectors.maxBy() | 最大值 |
Collectors.minBy() | 最小值 |
Collectors.summingDouble() | 总和 |
Collectors.summarizingDouble() | 得到的对象可以用来继续计算(getAverage(),getMax(),getCount()) |
@Test
public void test5() {
Long collect = employees.stream()
.collect(Collectors.counting());
System.out.println(collect);
Double avg = employees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
Optional<Double> max = employees.stream()
.map(Employee::getSalary)
.collect(Collectors.maxBy(Double::compare));
System.out.println(max.get());
Optional<Double> min = employees.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Double::compare));
System.out.println(min.get());
Double sum = employees.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
DoubleSummaryStatistics salary = employees.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(salary.getAverage());
System.out.println(salary.getMax());
System.out.println(salary.getCount());
}
3.3 分组、分区
方法 | 描述 |
---|
Collectors.groupingBy() | 分组 |
Collectors.partitioningBy() | 分区 |
List<Employee> employees = EmpData.findAllEmployee();
@Test
public void groupTest1() {
Map<Employee.Status, List<Employee>> statusListMap = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
statusListMap.keySet().forEach(System.out::println);
statusListMap.entrySet().forEach(System.out::println);
System.out.println(statusListMap);
}
VOCATION
BUSY
FREE
VOCATION=[Employee(id=4, name=田七, age=35, salary=4444.44, status=VOCATION)]
BUSY=[Employee(id=1, name=张三, age=18, salary=1111.11, status=BUSY), Employee(id=3, name=赵六, age=57, salary=3333.33, status=BUSY)]
FREE=[Employee(id=2, name=李四, age=49, salary=2222.22, status=FREE), Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE), Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE), Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE)]
{VOCATION=[Employee(id=4, name=田七, age=35, salary=4444.44, status=VOCATION)], BUSY=[Employee(id=1, name=张三, age=18, salary=1111.11, status=BUSY), Employee(id=3, name=赵六, age=57, salary=3333.33, status=BUSY)], FREE=[Employee(id=2, name=李四, age=49, salary=2222.22, status=FREE), Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE), Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE), Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE)]}
List<Employee> employees = EmpData.findAllEmployee();
@Test
public void groupTest2() {
Map<String, List<Employee>> emMap = employees.stream()
.collect(Collectors.groupingBy((employee) -> {
if (employee.getAge() <= 35) {
return "青年";
} else if (employee.getAge() > 20) {
return "老年";
} else {
return "少年";
}
}));
emMap.keySet().forEach(key -> {
System.out.println("======" + key + "======");
emMap.get(key).forEach(System.out::println);
});
emMap.forEach((k, v) -> {
System.out.println("======" + k + "======");
v.forEach(map -> {
System.out.println(map);
});
});
}
======青年======
Employee(id=1, name=张三, age=18, salary=1111.11, status=BUSY)
Employee(id=4, name=田七, age=35, salary=4444.44, status=VOCATION)
======老年======
Employee(id=2, name=李四, age=49, salary=2222.22, status=FREE)
Employee(id=3, name=赵六, age=57, salary=3333.33, status=BUSY)
Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE)
Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE)
Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE)
@Test
public void area1() {
Map<Boolean, List<Employee>> emMap = employees.stream()
.collect(Collectors.partitioningBy(e -> e.getSalary() > 2000.0));
emMap.forEach((k, v) -> {
System.out.println("======" + k + "======");
v.forEach(map -> {
System.out.println(map);
});
});
}
======false======
Employee(id=1, name=张三, age=18, salary=1111.11, status=BUSY)
======true======
Employee(id=2, name=李四, age=49, salary=2222.22, status=FREE)
Employee(id=3, name=赵六, age=57, salary=3333.33, status=BUSY)
Employee(id=4, name=田七, age=35, salary=4444.44, status=VOCATION)
Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE)
Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE)
Employee(id=2, name=李十四, age=49, salary=2222.22, status=FREE)
3.4 字符串操作
方法 | 描述 |
---|
Collectors.joining(",") | 字符串拼接 |
@Test
public void str() {
String str = employees.stream()
.map(Employee::getName)
.collect(Collectors.joining(","));
System.out.println(str);
}
张三,李四,赵六,田七,李十四,李十四,李十四