Stream
Stream 是Java8的新特性,并在后期版本进行了优化与扩展
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。Stream 讲的是计算!
特点
- Stream 自己不会存储元素。
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Steam 执行流程:
① Steam的实例化
② Steam中间操作----对数据源的数据进行处理,是一个中间操作
③ Steam 终止操作----一旦执行终止操作,就执行中间操作,是延迟操作,并产生结果,之后不能再被使用
流的实例化方式
1:通过集合
-
default Stream<E> stream() : 返回一个顺序流
-
default Stream<E> parallelStream() : 返回一个并行流
2:通过数组
-
static <T> Stream<T> stream(T[] array):
3:通过Stream.of()创建
-
public static<T> Stream<T> of(T... values) : Stream.of()
4:创建无限流
-
迭代---public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
-
生成---public static<T> Stream<T> generate(Supplier<T> s)
5:使用Stream.builder()–构建流,需要指定类型
-
Stream.Builder<String> add = Stream.<String>builder().add("a").add("b").add("c");
-
add.build().forEach(System.out::println);
6:IntStream/LongStream/DoubleStream
-
IntStream.range(1,3)
-
LongStream.rangeClosed(1, 3);
-
DoubleStream doubleStream= new Random().doubles(3);
7:创建一个空的流–使用静态方法Stream.empty()创建一个空的流:
- Stream stream = Stream.empty();
单元测试
//创建Steam的方式一:集合
@Test
public void test(){
List<Employee> employees=EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();//顺行流
Stream<Employee> parallel = employees.stream().parallel();//并行流
Stream<Employee> employeeStream = employees.parallelStream();//并行流
parallel.forEach(System.out::println);
System.out.println("*****************************");
stream.forEach(System.out::println);
}
//创建Steam的方式二:数组
@Test
public void test1(){
int[] arr=new int[]{1,2,3,9};
IntStream stream = Arrays.stream(arr);
System.out.println("*****************************");
stream.forEach(System.out::println);
}
//创建Steam的方式三:of()方法
@Test
public void test2(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 6, 9);
}
//创建Steam的方式四:创建无限流
@Test
public void test3(){
//迭代
Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);
//生成
Stream.generate(Math::random).limit(10).forEachOrdered(System.out::println);
}
//使用Stream.builder()构建流-要指定类型
@Test
public void test4(){
Stream.Builder<String> add = Stream.<String>builder().add("a").add("b").add("c");
add.build().forEach(System.out::println);
}
Stream的中间操作
1 筛选与切片
- filter(Predicate p) 接收 Lambda , 从流中排除某些元素
- distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
- limit(long maxSize) 截断流,使其元素不超过给定数量
- skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补。
2 映射
- map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
- mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
- mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
- flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
3 排序
- sorted()—产生一个新的流并按自然排序
- sorted(Comparator com)----产生一个新的流,按比较器顺序定制排序
测试类
public class Employee {
private int id;
private String name;
private int age;
private double salary;
private String sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String isSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Employee() {
System.out.println("Employee().....");
}
public Employee(int id) {
this.id = id;
System.out.println("Employee(int id).....");
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public Employee(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee(int id, String name,String sex, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
this.sex = sex;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
", sex=" + sex +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Employee employee = (Employee) o;
if (id != employee.id)
return false;
if (age != employee.age)
return false;
if (Double.compare(employee.salary, salary) != 0)
return false;
return name != null ? name.equals(employee.name) : employee.name == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + age;
temp = Double.doubleToLongBits(salary);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
测试数据
import java.util.ArrayList;
import java.util.List;
public class EmployeeData {
public static List<Employee> getEmployees(){
List<Employee> list = new ArrayList<>();
list.add(new Employee(1001, "马化腾","男",34, 6000.38));
list.add(new Employee(1002, "马云", "男",12, 9876.12));
list.add(new Employee(1003, "刘强东","男", 33, 3000.82));
list.add(new Employee(1004, "雷军","男", 26, 7657.37));
list.add(new Employee(1005, "李彦宏","男", 65, 5555.32));
list.add(new Employee(1006, "比尔盖茨","男", 42, 9500.43));
list.add(new Employee(1007, "任正非", "男",26, 4333.32));
list.add(new Employee(1008, "扎克伯格", "男",35, 2500.32));
list.add(new Employee(1009, "董明珠", "女",55, 9500.32));
list.add(new Employee(1010, "卢忠芳", "女",85, 7500.32));
list.add(new Employee(1011, "杨惠妍", "女",45, 2500.32));
list.add(new Employee(1012, "孙亚芳", "女",65, 10500.32));
return list;
}
}
单元测试
//筛选与切片
@Test
public void test(){
List<Employee> list=EmployeeData.getEmployees();
//过滤流--接收 Lambda,从流中排除某些元素
list.stream().filter(e->e.getSalary()>7000).forEach(System.out::println);
System.out.println("************************");
//截断流--使元素不超过指定数量
list.stream().limit(3).forEach(System.out::println);
System.out.println("************************");
//跳过元素--若流中元素不足 n 个,则返回一个空流。与limit()方法互补
list.stream().skip(3).forEach(System.out::println);
//筛选--通过流所生成元素的 hashCode() 和 equals() 去除重复元素
System.out.println("************************");
list.add(new Employee(1012,"刘强东",40,8522.00));
list.add(new Employee(1012,"刘强东",40,8522.00));
list.add(new Employee(1012,"刘强东",40,8522.00));
list.stream().distinct().forEach(System.out::println);
}
//映射
@Test
public void test1(){
//map操作
String[] strings=new String[]{"a","b","c","d"};
Arrays.stream(strings).map(String::toUpperCase).forEach(System.out::println);
System.out.println("************************");
//获取员工姓名长度大于3的姓名--先过滤按长度过滤名字的对象,然后映射出名字
List<Employee> list=EmployeeData.getEmployees();
list.stream().filter(e->e.getName().length()>3).map(Employee::getName).forEach(System.out::println);
//flatMap--流扁平化处理--接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
//常常用来处理流里面嵌套流的处理
System.out.println("************************");
Arrays.stream(strings).flatMap(StreamCenterOptionTest::fromStringStream).forEach(System.out::println);
}
public static Stream<Character> fromStringStream(String str){
ArrayList<Character> list=new ArrayList<>();
for (Character character : str.toCharArray()) {
list.add(character);
}
return list.stream();
}
//排序
@Test
public void test2(){
//sorted()---自然排序
List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);
list.stream().sorted().forEach(System.out::println);
System.out.println("************************");
//sorted(Comparator com)——定制排序
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted( (e1,e2) -> {
int ageValue = Integer.compare(e1.getAge(),e2.getAge());
if(ageValue != 0){
return ageValue;
}else{
return -Double.compare(e1.getSalary(),e2.getSalary());
}
}).forEach(System.out::println);
}
Stream 的终止操作
1 匹配与查找
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值;流进行了终止操作后,不能再次使用。
- allMatch(Predicate p) 检查是否匹配所有元素
- anyMatch(Predicate p) 检查是否至少匹配一个元素
- noneMatch(Predicate p) 检查是否没有匹配所有元素
- findFirst() 返回第一个元素
- findAny() 返回当前流中的任意元素
- count() 返回流中元素总数
- max(Comparator c) 返回流中最大值
- min(Comparator c) 返回流中最小值
- forEach(Consumer c)内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)
- 此迭代是并行的效率高
- forEachOrdered(Consumer c)内部迭代–按顺序迭代,此迭代是顺行的,效率较低
2- 归约
- reduce(T iden, BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回 T
- reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回 Optional
备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google用它来进行网络搜索而出名。
3-收集
- Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、Map)。
另外, Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例, - collect(Collector c)将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
单元测试
//匹配与查找
@Test
public void test(){
//allMatch()--检查是否匹配所有元素
List<Employee> employees = EmployeeData.getEmployees();
boolean b = employees.stream().allMatch(e -> e.getAge() > 18);
System.out.println(b);
System.out.println("**********************");
//anyMatch()--检查是否匹配一个元素
boolean b1 = employees.stream().anyMatch(e -> e.getSalary() > 5000);
System.out.println(b1);
System.out.println("**********************");
//noneMatch()--检查是否没有匹配元素
boolean b2 = employees.stream().noneMatch(e ->e.getName().startsWith("刘"));
System.out.println(b2);
System.out.println("**********************");
//findFirst()--返回流的第一个元素
employees.stream().findFirst().ifPresent(System.out::println);
System.out.println("**********************");
//findAny()---返回当前流中的任意元素
//非并行流中,在大多数情况下,两者都可能返回流的第一个元素,但是findAny()不提供此行为的任何保证。使用findAny()可以更快地从任何并行流中获取任何元素
Employee employee = employees.parallelStream().findAny().orElse(null);
System.out.println(employee);
System.out.println("**********************");
// count——返回流中元素的总个数
long count = employees.stream().filter(e -> e.getSalary() > 5000).count();
System.out.println(count);
System.out.println("**********************");
//max(Comparator c)——返回流中最大值--返回最高的工资
Optional<Double> max = employees.stream().map(Employee::getSalary).max(Double::compare);
System.out.println(max.orElse(null));
System.out.println("**********************");
//min(Comparator c)——返回流中最小值--返回最低工资的员工
employees.stream().min(Comparator.comparingDouble(Employee::getSalary)).ifPresent(System.out::println);
}
//归约
@Test
public void test1(){
//归约可以将流中元素反复结合起来,得到一个值。返回 T,经常和map映射操作搭配使用
int[] list=new int[]{1,2,3,8,0,78};
int reduce = Arrays.stream(list).reduce(0, Integer::sum);
System.out.println(reduce);
System.out.println("**********************");
List<Employee> employees = EmployeeData.getEmployees();
//employees.stream().map(Employee::getSalary).reduce(Double::sum).ifPresent(System.out::println);
employees.stream().map(Employee::getSalary).reduce((d1,d2)->d1+d2).ifPresent(System.out::println);
}
//收集
@Test
public void test2(){
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().filter(e->e.getSalary()>6000).collect(Collectors.toList()).forEach(System.out::println);
System.out.println("**********************");
employees.stream().filter(e->e.getSalary()>6000).collect(Collectors.toSet()).forEach(System.out::println);
}
Collector 接口中方法:
-
1 List toList() 把流中元素收集到List
举例:List<Employee> emps= list.stream().collect(Collectors.toList());
-
2 Set toSet() 把流中元素收集到Set
举例:Set<Employee> emps= list.stream().collect(Collectors.toSet());
-
3 Collection toCollection() 把流中元素收集到创建的集合
举例:Collection<Employee>emps=list.stream().collect(Collectors.toCollection(ArrayList::new));
-
4 Long counting() 计算流中元素的个数
举例:long count = list.stream().collect(Collectors.counting());
-
5 Integer summingInt() 对流中元素的整数属性求和
举例:int total=list.stream().collect(Collectors.summingInt(Employee::getAge));
-
6 Double averagingInt() 计算流中元素Integer属性的平均值
举例:double avg = list.stream().collect(Collectors.averagingInt(Employee::getAge));
-
7 IntSummaryStatistics summarizingInt() 收集流中Integer属性的统计值。如:平均值
举例:int SummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getAge
)); -
- String joining() String 连接流中每个字符串
举例:String str= list.stream().map(Employee::getName).collect(Collectors.joining());
举例:String str= list.stream().map(Employee::getName).collect(Collectors.joining(",", "{", "}")));
举例:String str= list.stream().map(Employee::getName).collect(Collectors.joining(","))
;
- String joining() String 连接流中每个字符串
-
9: Optional maxBy() 根据比较器选择最大值
举例:Optional<Emp>max= list.stream().collect(Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary)));
-
10:Optional minBy() 根据比较器选择最小值
举例:Optional<Emp> min = list.stream().collect(Collectors.minBy(Comparator.comparingDouble(Employee::getSalary)));
-
11:reducing() 从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值
举例:int total=list.stream().collect(Collectors.reducing(0, Employee::getAge, Integer::sum));
-
12:collectingAndThen() 转换函数返回的类型 包裹另一个收集器,对其结果转换函数
举例:int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
-
13:Map<K, List> groupingBy() 根据某属性值对流分组,属性为K,结果为V
举例:Map<String, List<Employee>> map= list.stream().collect(Collectors.groupingBy(Employee::getName));
-
14:Map<Boolean, List> partitioningBy() 收集后根据true或false进行分区
举例:employees.stream().collect(Collectors.partitioningBy(employee -> employee.getSalary()>8000, Collectors.mapping(Employee::getName,Collectors.counting()))).forEach((Key, value)-> System.out.println(Key+"----"+value));
-
15:mapping()方法会将结果应用到另一个收集器上。
举例:employees.stream().collect(Collectors.partitioningBy(employee -> employee.getSalary()>8000, Collectors.mapping(Employee::getName,Collectors.toList()))).forEach((Key, value)-> System.out.println(Key+"----"+value));
-
16:flatMapping()–类似于Collectors.mapping() 方法,但粒度更细。两者都带一个函数和一个收集器参数用于收集元素,但flatMapping函数接收元素流,然后通过收集器进行累积操作,一般用于collect()里对嵌套流的处理
-
17:filtering()–类似Stream filter()方法,用于过滤输入元素,常和groupingBy/partitioningBy搭配使用
-
18:toUnmodifiableMap()–将元素聚集到一个不可修改的Map,Map中的对象地址不可修改,里面的对象若支持修改的话,其实也还是可以修改的。
-
19:toUnmodifiableSet()—将元素聚集到一个不可修改的HashSet
-
20:toMap()—将元素聚集到一个map中
-
21:toConcurrentMap()—将元素聚集到一个支持并发的concurrentHashMap中
-
22:toUnmodifiableList()—将元素聚集到一个不可修改的ArrayList
-
23:groupingByConcurrent()—类似groupingBy(),但其聚集的集合是concurrentHashMap支持并发,可以提高并行流分组的效率
-
24:teeing()–返回一个由两个下游收集器组成的收集器。传递给生成的收集器的每个元素都由下游收集器处理,然后使用指定的合并函数将它们的结果合并到最终结果中。
支持使用两个独立的收集器收集流,然后使用提供的双功能合并结果。
单元测试
//Collectors methods
@Test
public void test3() {
List<Employee> employees = EmployeeData.getEmployees();
//Collectors.reducing()--从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值
int total = employees.stream().collect(Collectors.reducing(0, Employee::getAge, Integer::sum));
System.out.println(total);
System.out.println("**********************");
//Collectors.collectingAndThen()--转换函数返回的类型 包裹另一个收集器,对其结果转换函数
int how = employees.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
System.out.println(how);
System.out.println("**********************");
//Collectors.groupingBy()---分组
Map<String, Long> collect = employees.stream().collect(Collectors.groupingBy(e -> {
if (e.getAge() > 60)
return "老年人";
else if (e.getAge() > 40)
return "中年人";
else
return "青年人";
}, Collectors.counting()));
collect.forEach((Key, value) -> System.out.println(Key + "----" + value));
System.out.println("**********************");
//Collectors.partitioningBy() 收集后根据true或false进行分区
// Collectors.mapping() 方法会将结果应用到另一个收集器上。
//----按工资大于8000的用户进行分组,分成2组,大于8000的为true,小于的为false并映射出姓名放入list集合中
employees.stream().collect(Collectors.partitioningBy(employee -> employee.getSalary() > 8000, Collectors.mapping(Employee::getName, Collectors.toList()))).forEach((Key, value) -> System.out.println(Key + "----" + value));
System.out.println("**********************");
//Collectors.filtering()--过滤输出元素--按男女分组过滤出工资大于5000的员工姓名
employees.stream().collect(Collectors.groupingBy(Employee::isSex, Collectors.filtering(employee -> employee.getSalary() > 5000, Collectors.mapping(Employee::getName, Collectors.toList())))).forEach((Key, value) -> System.out.println(Key + "----" + value));
System.out.println("**********************");
//Collectors.flatMapping()--对collect里嵌套流的处理
employees.stream().collect(Collectors.partitioningBy(employee -> employee.getSalary() > 8000, Collectors.flatMapping(s -> Stream.of(s.getName()), Collectors.joining(";", "{", "}")))).forEach((Key, value) -> System.out.println(Key + "----" + value));
System.out.println("**********************");
//Collectors.groupingByConcurrent()--并行分组处理
employees.stream().collect(Collectors.groupingByConcurrent(Employee::isSex, Collectors.counting())).forEach((Key, value) -> System.out.println(Key + "----" + value));
System.out.println("**********************");
//Collectors.toUnmodifiableSet()--将元素聚集到一个不可修改的HashSet
employees.stream().collect(Collectors.mapping(Employee::getName, Collectors.toUnmodifiableSet())).forEach(System.out::println);
System.out.println("**********************");
//Collectors.toUnmodifiableList()--将元素聚集到一个不可修改的ArrayList
employees.stream().map(Employee::getName).collect(Collectors.toUnmodifiableList()).forEach(System.out::println);
System.out.println("**********************");
//Collectors.toUnmodifiableMap()--将元素聚集到一个不可修改的HashMap
employees.stream().collect(Collectors.toUnmodifiableMap(Employee::getId, employee -> {
List<Employee> employeeList = new ArrayList<>();
employeeList.add(employee);
return employeeList;
})).forEach((Key, value) -> System.out.println(Key + "----" + value));
System.out.println("**********************");
//Collectors.teeing()-返回一个由两个收集器组成的收集器。传递给生成的收集器的每个元素都由两个子收集器处理,然后使用指定的合并函数将它们的结果合并到最终结果中。
Double collect1 = employees.stream().collect(Collectors.teeing(Collectors.averagingDouble(Employee::getSalary),Collectors.summingDouble(Employee::getSalary),Double::max));
System.out.println(collect1);
}
流的其他操作
- concat()–
此方法创建一个延迟连接的流,其元素是firstStream的所有元素,后跟secondStream的所有元素。 如果两个输入流都是有序的,则对所得到的流进行排序。如果任一输入流是并行的,则得到的流是平行的。 - peek()(Consumer<? super T> action)-------stream.peek的操作是返回一个新的stream的,主要是用来debug调试的,因此使用steam.peek()必须对流进行一次处理再产生一个新的stream
- ofNullable(T t)-如果此流不为null,则ofNullable(T)方法将返回包含单个元素的顺序Stream,否则该方法将返回空Stream。
- takeWhile()(Predicate<? super T> predicate)–takeWhile() 方法使用一个断言作为参数,获取满足断言条件的元素直到断言为false为止。丢弃后面的元素,如果第一个值不满足断言条件,将返回一个空的 Stream。
- dropWhile()(Predicate<? super T> predicate)—dropWhile 方法和 takeWhile 作用相反的,使用一个断言作为参数,从Stream中依次删除满足断言条件的元素,直到不满足条件为止结束删除
Spliterator接口
–Spliterator用来遍历和分割序列,它是为了并行执行而设计的;集合实现了 Spliterator 接口,提供了一个 spliterator()方法
- tryAdvance() 方法的行为类似于普通的 Iterator ,因为它会按顺序一个一个使用 Spliterator 中的元素,并且如果还有其他元素要遍历就返回 true,否则返回false
- trySplit() --Spliterator最核心的方法;把一些元素划出去分给第二个 Spliterator (由该方法返回且装载已分割的元素),分割的Spliterator被用于每个子线程进行处理,从而达到并发处理的效果。当分割器Spliterator不能继续分割,则返回null。
如果两个或多个线程在同一个spliterator上并发运行,则拆分和遍历的行为是不确定的。如果原始线程将一个spliterator移交给另一个线程进行处理,最好是在使用tryAdvance()消费任何元素之前进行切换
理想的trySplit()方法有效地(无遍历)将其元素精确地分成两半,允许平衡并行计算。许多偏离这种理想仍然非常有效; - forEachRemaining()–在当前线程中串行对剩余元素执行迭代操作,直到所有元素都被处理或抛出异常。 如果是串行的,则按相关顺序执行操作。异常被转发给调用者。
- estimateSize()—该接口是返回forEachRemaining遍历所遇到的元素数量的估计值,如果为无穷大,未知数或计算成本太高,则返回Long.MAX_VALUE。
单元测试
//Stream other methods test
@Test
public void test4(){
//concat()--两个数字类型的stream进行合并
Stream<Integer> resultingStream = Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6));
System.out.println("**********************");
//peek()
Stream.of("one", "two", "three","four").filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
System.out.println("**********************");
//takeWhile()方法使用一个断言作为参数,获取满足断言条件的元素直到断言为false为止。丢弃后面的元素,如果第一个值不满足断言条件,将返回一个空的 Stream。
Stream.of("a","b","c","","e","f").takeWhile(s->!s.isEmpty()).forEach(System.out::print);
System.out.println();
System.out.println("**********************");
//dropWhile方法和takeWhile方法作用相反的,使用一个断言作为参数,从Stream中依次删除满足断言条件的元素,直到不满足条件为止结束删除
Stream.of("a","b","c","","e","f").dropWhile(s->!s.isEmpty()).forEach(System.out::print);
System.out.println();
System.out.println("**********************");
//spliterator().tryAdvance()
Arrays.asList("leo", "ben", "jack").spliterator().tryAdvance(System.out::println);
System.out.println("**********************");
//spliterator().trySplit()---支持并发
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 20; i++) list.add(i + 1);
Spliterator<Integer> spliterator1 = list.spliterator();//spliterator1 有20个元素(1-20)
Spliterator<Integer> spliterator2 = spliterator1.trySplit(); //spliterator1中有10个元素(11-20),spliterator2中有10个元素(1-10)
Spliterator<Integer> spliterator3 = spliterator1.trySplit(); //spliterator1中有5个元素(16-20),spliterator2中有10个元素(1-10),spliterator3中有5个元素(11-15)
Spliterator<Integer> spliterator4 = spliterator2.trySplit();//spliterator1中有5个元素(16-20),spliterator2中有5个元素(6-10);spliterator3中有5个元素(11-15),spliterator4中有5个元素(1-5)
Spliterator<Integer> spliterator5 = spliterator2.trySplit();//spliterator1中有5个元素(16-20),spliterator2中有3个元素(8-10);spliterator3中有5个元素(11-15),spliterator4中有5个元素(1-5),spliterator5中有2个元素(6-7)
int i = 1;
for (Spliterator<Integer> numThread : Arrays.asList(spliterator1, spliterator2,spliterator3,spliterator4,spliterator5)) {
Thread thread = new Thread(() -> numThread.forEachRemaining(System.out::println));
thread.setName("spliterator"+i);
System.out.println("剩余元素个数:"+numThread.getExactSizeIfKnown());
System.out.println("该对象具有的特征值:"+numThread.characteristics());
//如果Spliterator的list是通过Comparator排序的,则返回Comparator
//如果Spliterator的list是自然排序的 ,则返回null
//其他情况下抛错
//System.out.println("返回该对象的比较器:"+numThread.getComparator());
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getName()+"---------------------------");
i++;
}
}