5.2 筛选 / 切片
filter:接收 Lambda ,从流中排除某些元素
limit:截断流,使其元素不超过给定数量
skip(n):跳过元素,返回一个舍弃了前n个元素的流;若流中元素不足n个,则返回一个空 流;与 limit(n) 互补
distinct:筛选,通过流所生成的 hashCode() 与 equals() 取除重复元
中间 操作 //没有终止操作,就不会有输出
- 内部迭代:迭代操作由 Stream API 完成
- 外部迭代:我们通过迭代器完成
List5.3 映射 (常用)emps = Arrays.asList( new Employee(101, "Z3", 19, 9999.99), new Employee(102, "L4", 20, 7777.77), new Employee(103, "W5", 35, 6666.66), new Employee(104, "Tom", 44, 1111.11), new Employee(105, "Jerry", 60, 4444.44) ); @Test public void test01(){ emps.stream() .filter((x) -> x.getAge() > 35) .limit(3) //短路?达到满足不再内部迭代 .distinct() //他是通过 HashCode 和equals实现 实体类中 要重写这个方法 .skip(1) .forEach(System.out::println); }
- map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
- flatMap:接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流
@Test
public void test02(){
List list = Arrays.asList("aaa", "bbb", "ccc","eee",);
list.stream()
.map((str) -> str.toUpperCase())
//里面是一个映射函数
.forEach(System.out::println);
}
FlatMap 的结果
public Stream5.4 排序filterCharacter(String str){ List list = new ArrayList<>(); for (char c : str.toCharArray()) { list.add(c); } return list.stream(); } @Test public void test03(){ List list = Arrays.asList("aaa", "bbb", "ccc","ddd","eee"); Test02 test02 = new Test02(); list.stream() // 把这个数组里数 分别转换为流,再连接为一个流 .flatMap( 类名::filterCharacter) //静态的引用 .forEach(System.out::println); }
Comparable:自然排序
- sorted():自然排序
- sorted(Comparator c):定制排序
@Test
public void test04(){
List list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
list.stream()
.sorted() //默认的系统排序comparaTo()
.forEach(System.out::println);
}
Comparator:定制排序
@Test
public void test05(){
emps.stream()
.sorted((e1, e2) -> { //compara()
if (e1.getAge().equals(e2.getAge())){
//先判断年龄是否一样 ,再按照姓名排序
return e1.getName().compareTo(e2.getName());
} else {
//年龄优先排序
return e1.getAge().compareTo(e2.getAge());
}
})
.forEach(System.out::println);
}
终止操作
5.5 查找 / 匹配allMatch:检查 一个条件 是否匹配所有元素
anyMatch:检查是否至少匹配一个元素
noneMatch:检查是否没有匹配所有元素
findFirst:返回第一个元素
findAny:返回当前流中的任意元素
count:返回流中元素的总个数
max:返回流中最大值
min:返回流中最小值
public enum Status {
FREE, BUSY, VOCATION;
}
@Test
public void test01(){
List list = Arrays.asList(Status.FREE, Status.BUSY, Status.VOCATION);
boolean flag1 = list.stream() //获得流
.allMatch((s) -> s.equals(Status.BUSY));
//检查 所有的是否是全符合 忙碌状态
System.out.println(flag1);
boolean flag2 = list.stream()
.anyMatch((s) -> s.equals(Status.BUSY));
//是否能找到一个 符合里面的条件
System.out.println(flag2);
boolean flag3 = list.stream()
.noneMatch((s) -> s.equals(Status.BUSY));
//检查是否 没有这个条件的 元素
System.out.println(flag3);
// 避免空指针异常
Optional op1 = list.stream()
.findFirst();
// 如果Optional为空 找一个替代的对象
Status s1 = op1.orElse(Status.BUSY);
System.out.println(s1);
Optional op2 = list.stream()
.findAny();
System.out.println(op2);
long count = list.stream()
.count();
System.out.println(count);
}
5.6 归约 / 收集
reduce:
- 归约:reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的数据反复结合起来,得到一个值
- 收集:collect 将流转换成其他形式;接收一个 Collector 接口的实现,用于给流中元素做汇总的方法
@Test
public void test01(){
List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Integer integer = list.stream()
.reduce(0, (x, y) -> x + y); //相当于与不断地递归相加
System.out.println(integer);
}
collect:
List5.7 需求解决emps = Arrays.asList( new Employee(101, "Z3", 19, 9999.99), new Employee(102, "L4", 20, 7777.77), new Employee(103, "W5", 35, 6666.66), new Employee(104, "Tom", 44, 1111.11), new Employee(105, "Jerry", 60, 4444.44) ); @Test public void test02(){ //放入List List list = emps.stream() .map(Employee::getName) .collect(Collectors.toList()); list.forEach(System.out::println); //放入Set Set set = emps.stream() .map(Employee::getName) .collect(Collectors.toSet()); set.forEach(System.out::println); //放入linkedHashSet linkedHashSet linkedHashSet = emps.stream() .map(Employee::getName) .collect(Collectors.toCollection(linkedHashSet::new)); linkedHashSet.forEach(System.out::println); } @Test public void test03(){ //总数 Long count = emps.stream() .collect(Collectors.counting()); System.out.println(count); //平均值 Double avg = emps.stream() .collect(Collectors.averagingDouble(Employee::getSalary)); System.out.println(avg); //总和 Double sum = emps.stream() .collect(Collectors.summingDouble(Employee::getSalary)); System.out.println(sum); //最大值 Optional max = emps.stream() .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); System.out.println(max.get()); //最小值 Optional min = emps.stream() .map(Employee::getSalary) .collect(Collectors.minBy(Double::compare)); System.out.println(min.get()); } @Test public void test04(){ //分组 Map > map = emps.stream() .collect(Collectors.groupingBy(Employee::getId)); System.out.println(map); //多级分组 Map >> mapMap = emps.stream() .collect(Collectors.groupingBy(Employee::getId, Collectors.groupingBy((e) -> { if (e.getAge() > 35) { return "开除"; } else { return "继续加班"; } }))); System.out.println(mapMap); //分区 Map > listMap = emps.stream() .collect(Collectors.partitioningBy((e) -> e.getSalary() > 4321)); System.out.println(listMap); } @Test public void test05(){ //总结 DoubleSummaryStatistics dss = emps.stream() .collect(Collectors.summarizingDouble(Employee::getSalary)); System.out.println(dss.getMax()); System.out.println(dss.getMin()); System.out.println(dss.getSum()); System.out.println(dss.getCount()); System.out.println(dss.getAverage()); //连接 String str = emps.stream() .map(Employee::getName) .collect(Collectors.joining("-")); //可传入分隔符 System.out.println(str); }
怎样使用 map 和 reduce 数一数流中有多少个 Employee 呢?
Listemps = Arrays.asList( new Employee(101, "Z3", 19, 9999.99), new Employee(102, "L4", 20, 7777.77), new Employee(103, "W5", 35, 6666.66), new Employee(104, "Tom", 44, 1111.11), new Employee(105, "Jerry", 60, 4444.44) ); @Test public void test02(){ Optional result = emps.stream() .map((e) -> 1) .reduce(Integer::sum); System.out.println(result.get());
给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?(如:给定【1,2,3,4,5】,返回【1,4,9,16,25】)
@Test
public void test01(){
List list = Arrays.asList(1, 2, 3, 4, 5);
list.stream()
.map((x) -> x * x)
.forEach(System.out::println);
}
5.8 并行流
Fork / Join 框架: Fork / Join 框架与传统线程池的区别: Fork / Join 实现:
- 并行流:就是把一个内容分成几个数据块,并用不同的线程分别处理每个数据块的流
- Java 8 中将并行进行了优化,我们可以很容易的对数据进行操作;Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与串行流之间切换
public class ForkJoinCalculate extends RecursiveTaskJava 8 并行流 / 串行流:{ private static final long serialVersionUID = 1234567890L; private long start; private long end; private static final long THRESHPLD = 10000; public ForkJoinCalculate(long start, long end) { this.start = start; this.end = end; } @Override protected Long compute() { long length = end - start; if (length <= THRESHPLD) { long sum = 0; for (long i = start; i <= end; i++) { sum += i; } } else { long middle = (start + end) / 2; ForkJoinCalculate left = new ForkJoinCalculate(start, end); left.fork(); //拆分子任务 压入线程队列 ForkJoinCalculate right = new ForkJoinCalculate(middle + 1, end); right.fork(); return left.join() + right.join(); } return null; } } public class TestForkJoin { @Test public void test01(){ Instant start = Instant.now(); ForkJoinPool pool = new ForkJoinPool(); ForkJoinCalculate task = new ForkJoinCalculate(0, 100000000L); Long sum = pool.invoke(task); System.out.println(sum); Instant end = Instant.now(); System.out.println(Duration.between(start, end).getNano()); } @Test public void test02(){ Instant start = Instant.now(); Long sum = 0L; for (long i = 0; i < 100000000L; i++) { sum += i; } Instant end = Instant.now(); System.out.println(Duration.between(start, end).getNano()); } }
@Test
public void test03(){
//串行流(单线程):切换为并行流 parallel()
//并行流:切换为串行流 sequential()
LongStream.rangeClosed(0, 100000000L)
.parallel() //底层:ForkJoin
.reduce(0, Long::sum);
}



