StreamAPI
Stream是java8中处理集合的抽象概念,对集合可以执行复杂的查找、过滤、映射数据等操作。
Stream是数据的渠道,用于操作数据源生成元素序列。
注意:
1.Stream不会存储元素
2.Stream不会改变源对象,会返回一个持有结果的新的Stream
3.Stream操作会有延迟执行。
Stream操作三步走:
1.创建Stream
一个类似集合、数组,获取一个流
2.中间操作
3.终端操作
一个终止操作,执行中间操作链,并产生结果
创建流
Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
default Stream<E> stream() : 返回一个顺序流
default Stream<E> parallelStream() : 返回一个并行流
由数组创建流
Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)
由值创建流
可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。
public static<T> Stream<T> of(T... values) : 返回一个流
由函数创建流:创建无限流
可以使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流。
迭代
public static<T> Stream<T> iterate(final T seed, final
UnaryOperator<T> f)
生成
public static<T> Stream<T> generate(Supplier<T> s) :
public void test1(){
//1.可以通过collections系列集合提供的stream()或parallelStream()
ArrayList<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
//2.通过Arrays中的静态方法 stream()获取连接
Employee[] emps=new Employee[10];
Stream<Employee> stream1 = Arrays.stream(emps);
//3.通过stream类的静态方法
Stream<String> stream2 = Stream.of("aa", "bb", "cc");
//4.创建无限流
//迭代
Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2);
stream3.forEach(System.out::println);
//生成
Stream<Double> doubleStream = Stream.generate(() -> Math.random());
doubleStream.forEach(System.out::println);
}
Stream中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
public void test4(){
employees.stream()
.filter((e)->e.getSalary()>5000)
.limit(2)
.forEach(System.out::println);
}
@Test
public void test5(){
employees.stream()
.filter((e)->e.getAge()>35)
.skip(1)
.forEach(System.out::println);
}
@Test
public void test6(){
employees.stream()
.filter(e->e.getSalary()>8000)
.distinct()
.forEach(System.out::println);
}
@Test
public void test2(){
Stream<Employee> stream = employees.stream();
Stream<Employee> resStream = stream.filter((e) -> e.getAge() > 35);
resStream.forEach(System.out::println);
}
//外部迭代
@Test
public void test3(){
Iterator<Employee> iterator = employees.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
映射
@Test
public void test7(){
List<String> list=Arrays.asList("aaa","bbb","ccc","ddd");
list.stream()
.map((str)->str.toUpperCase())
.forEach(System.out::println);
System.out.println("---------------");
employees.stream()
.map(Employee::getName)
.distinct()
.forEach(System.out::println);
System.out.println("---------------");
/*list.stream()
.map(TestStreamAPI::filterCharacter)
.forEach(e->e.forEach(System.out::println));*/
//与上面的效果相同
list.stream()
.flatMap(TestStreamAPI::filterCharacter)
.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str){
List<Character> list=new ArrayList<Character>();
for(Character ch:str.toCharArray()){
list.add(ch);
}
return list.stream();
}
排序
/*
* sorted() --自然排序--Comparable
* sorted(Comparator com)--定制排序--Comparator
* */
@Test
public void test1(){
List<String> list= Arrays.asList("ee","aa","bb","cc","dd");
List<Employee> employees= Arrays.asList(
new Employee("张三",18,8888),
new Employee("李四",38,8877),
new Employee("王五",50,8328),
new Employee("赵柳",15,8448),
new Employee("田七",12,8548),
new Employee("田七",12,8548),
new Employee("田七",12,8548)
);
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("----------------");
//定制排序
employees.stream()
.sorted((o1,o2)->{
if(o1.getSalary()>o2.getSalary()) return -1;
else if(o1.getSalary()<o2.getSalary()) return 1;
else return 0;
}).forEach(System.out::println);
}
}
终止操作
终端操作会从流的流水线生成结果。其结果可以使任何不是流的值,例如:List、Integer 甚至是void。
List<Employee1> employee1s= Arrays.asList(
new Employee1("张三",18,9999, Employee1.Status.FREE),
new Employee1("李四",58,5395, Employee1.Status.BUSY),
new Employee1("王五",36,3393, Employee1.Status.BUSY),
new Employee1("赵柳",36,6666, Employee1.Status.VACATION),
new Employee1("田七",12,8888, Employee1.Status.BUSY)
);
public void test1(){
boolean res = employee1s.stream()
.allMatch((e) -> e.getSalary() > 6000);
System.out.println(res);
boolean res2 = employee1s.stream()
.noneMatch((e) -> e.getStatus().equals(Employee1.Status.BUSY));
System.out.println(res2);
Optional<Employee1> first = employee1s.stream()
.findFirst();
System.out.println(first);
//parallelStream是多线程根据匹配的条件去寻找,如果使用Stream去寻找只能顺序找到第一个符合条件的
System.out.println("findAny");
Optional<Employee1> any = employee1s.parallelStream()
.filter(e->e.getStatus().equals(Employee1.Status.BUSY))
.findAny();
System.out.println(any.get());
long count = employee1s.stream()
.count();
System.out.println(count);
System.out.println("---------------");
Optional<Employee1> first1 = employee1s.stream()
.sorted((o1, o2) -> Double.compare(o2.getSalary(), o1.getSalary()))
.findFirst();
System.out.println("找到的工资最高的人的信息"+first1);
//最高的工资的人的信息
Optional<Employee1> maxSalary = employee1s.stream()
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println("最高的工资是"+maxSalary);
//最低的工资的人的信息
Optional<Employee1> min = employee1s.stream()
.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println("最低的工资是"+min);
//换一种写法
Optional<Double> minSalary = employee1s.stream()
.map(Employee1::getSalary)
.min(Double::compare);
System.out.println(minSalary);
}
public void test1(){
List<Integer> list= Arrays.asList(1,2,3,4,5,6,7,8,9);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
System.out.println("--------");
Optional<Double> sumSalary = employee1s.stream()
.map(Employee1::getSalary)
.reduce(Double::sum);
System.out.println(sumSalary.get());
}
Collector接口中方法的实现决定了如何对流执行收集操作。这里提供了很多静态方法。
public void test2(){
List<String> list = employee1s.stream()
.map(Employee1::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
/*Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}*/
System.out.println("collect--set");
Set<String> set = employee1s.stream()
.map(Employee1::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("如果放在hashSet中可以这样改写");
HashSet<String> hashSet = employee1s.stream()
.map(Employee1::getName)
.collect(Collectors.toCollection(HashSet::new));
hashSet.forEach(System.out::println);
System.out.println("如果放在linkedList中,这样改写");
LinkedList<String> linkedList = employee1s.stream()
.map(Employee1::getName)
.collect(Collectors.toCollection(LinkedList::new));
linkedList.forEach(System.out::println);
}
public void test3(){
//总数
Long count = employee1s.stream()
.collect(Collectors.counting());
System.out.println(count);
Optional<Double> max = employee1s.stream()
.map(Employee1::getSalary)
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1, e2)));
System.out.println(max);
Double avgSalary = employee1s.stream()
.collect(Collectors.averagingDouble(Employee1::getSalary));
System.out.println(avgSalary);
//求sum min max count avg
DoubleSummaryStatistics sumSalary = employee1s.stream()
.collect(Collectors.summarizingDouble(Employee1::getSalary));
System.out.println(sumSalary);
Optional<Employee1> maxS = employee1s.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(maxS);
}
//分组
@Test
public void test6(){
Map<Double, List<Employee1>> collect = employee1s.stream()
.collect(Collectors.groupingBy(Employee1::getSalary));
System.out.println(collect);
}
//多集分组
@Test
public void test7(){
Map<Double, Map<Employee1.Status, List<Employee1>>> collect = employee1s.stream()
.collect(Collectors.groupingBy(Employee1::getSalary, Collectors.groupingBy(Employee1::getStatus)));
System.out.println(collect);
}
//连接字符串
@Test
public void test8(){
String str = employee1s.stream()
.map(Employee1::getName)
.collect(Collectors.joining(","));
System.out.println(str);
}
接口中的默认方法与静态方法
接口中默认方法使用 default 关键字修饰
例如:
interface MyFunc<T>{
T func(int a);
default String getName(){
return "hello world";
}
}
接口默认方法的类优先原则
如果一接口中定义一个默认方法,另一父类或接口中又定义一同名方法。
1.选择父类的方法
2.如果继承多个接口,有着相同的名称、参数列表的方法。那么本来必须覆盖该方法解决冲突。
接口中的静态方法
可以通过接口名.方法名 的方式调用该静态方法。