Java8中有两大最为重要的改变。
第一个是 Lambda表达式;另外一个则是 Stream API (java.util.stream.*)。
Stream是 Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。
使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API提供了一种高效且易于使用的处理数据的方式。
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!”
注意:
① Stream自己不会存储元素。
② Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
● 创建Stream
一个数据源(如集合、数组),获取一个流
● 中间操作
一个中间操作链,对数据源的数据进行处理,
● 终止操作
一个终止操作,执行中间操作链,并产生结果
● default Stream stream() :返回一个顺序流
● default Stream parallelStream() :返回一个并行流
//1,可以通过 Collection 系列集合提供的 stream() 或者 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
Java8 中的Arrays 的静态方法stream()可以获取数组流:
● staticStreamstream(T[] array):返回一个流
//2.通过 Arrays 中的静态方法 stream() 获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)
可以使用静态方法Stream. of(),通过显示值创建一个流。它可以接收任意数量的参数。
public staticStreamof(T… . values) :返回一个流
//3.通过 Stream 类中的静态方法 of()
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
可以使用静态方法Stream.iterate()和Stream. generate(),创建无限流。
● 迭代
public staticStream iterate(final T seed,finalUnaryOperator f)
● 生成
public staticStreamgenerate (Supplier s) :
//4.创建无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(10).forEach(System.out::println);
//生成
Stream.generate(() -> Math.random())
.limit(5)
.forEach(System.out::println);
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
● filter() 使用
@Test
public void test1() {
//内部迭代:迭代操作由Stream API完成
//中间操作:不会执行任何操作
Stream<Employee> stream = employees.stream()
.filter((e -> {
return e.getAge() > 35;
}));
//中间操作:一次性执行全部内容,即“惰性求值”
stream.forEach(System.out::println);
● limit() 使用
@Test
public void test3() {
employees.stream()
.filter((e) -> e.getSalary() > 5000)
.limit(2)
.forEach(System.out::println);
}
● skip()、distinct() 使用
@Test
public void test4() {
employees.stream()
.filter((e) -> e.getSalary() > 5000)
.skip(2)
.distinct()
.forEach(System.out::println);
}
● map()、flatMap() 使用
@Test
public void test5() {
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
list.stream()
.map((str) -> str.toUpperCase())
.forEach(System.out::println);
System.out.println("----------------------");
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
System.out.println("----------------------");
// Stream> stream = list.stream()
// .map(TestStreamAPI2::filterCharacter);
// stream
// .forEach((sm) -> {
// sm.forEach(System.out::println);
// });
System.out.println("----------------------");
Stream<Character> sm = list.stream()
.flatMap(TestStreamAPI2::filterCharacter);
sm.forEach(System.out::println);
}
● sorted() 使用
@Test
public void test6() {
List<String> list = Arrays.asList("ccc", "aaa", "bbb", "ddd", "eee");
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("----------------------");
employees.stream()
.sorted((e1, e2) -> {
if (e1.getAge().equals(e2.getAge())) {
return e1.getName().compareTo(e2.getName());
} else {
return -e1.getAge().compareTo(e2.getAge());
}
}).forEach(System.out::println);
}
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
● allMatch()、anyMatch()、findFirst()…使用
@Test
public void test2() {
long count = employees.stream()
.count();
System.out.println(count);
Optional<Employee1> op1 = employees.stream()
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op1.get());
Optional<Double> min = employees.stream()
.map(Employee1::getSalary)
.min(Double::compare);
System.out.println(min);
}
@Test
public void test1() {
boolean b = employees.stream()
.allMatch((e) -> e.getStatus().equals(Employee1.Status.Busy));
System.out.println(b);
System.out.println("------------------");
boolean b1 = employees.stream()
.anyMatch((e) -> e.getStatus().equals(Employee1.Status.Busy));
System.out.println(b1);
boolean b3 = employees.stream()
.noneMatch((e) -> e.getStatus().equals(Employee1.Status.Busy));
System.out.println(b3);
Optional<Employee1> op = employees.stream()
.sorted((e1, e2) -> -Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(op.get());
Optional<Employee1> op2 = employees.stream()
.filter(e -> e.getStatus().equals(Employee1.Status.Free))
.findAny();
System.out.println(op2.get());
}
备注:map 和 reduce 的连接通常称为map-reduce 模式,因 Google 用它
来进行网络搜索而出名。
● map()、reduce() 使用
@Test
public void test3() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
Optional<Double> op = employees.stream()
.map(Employee1::getSalary)
.reduce(Double::sum);
System.out.println(op.get());
}
Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:
● toList()、maxBy()、partitioningBy()… 使用
@Test
public void test10() {
String str = employees.stream()
.map(Employee1::getName)
.collect(Collectors.joining());
System.out.println(str);
}
@Test
public void test9() {
DoubleSummaryStatistics ds = employees.stream()
.collect(Collectors.summarizingDouble(Employee1::getSalary));
System.out.println(ds.getAverage());
System.out.println(ds.getMax());
System.out.println(ds.getCount());
}
//分区
@Test
public void test8() {
Map<Boolean, List<Employee1>> pb = employees.stream()
.collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
System.out.println(pb);
}
//多级分组
@Test
public void test7() {
Map<Employee1.Status, Map<String, List<Employee1>>> map = employees.stream()
.collect(Collectors.groupingBy(Employee1::getStatus, Collectors.groupingBy((e) -> {
if (e.getAge() <= 35) {
return "青年";
} else if (e.getAge() <= 50) {
return "中年";
} else {
return "老年";
}
})));
Set<Map.Entry<Employee1.Status, Map<String, List<Employee1>>>> entries = map.entrySet();
for (Map.Entry<Employee1.Status, Map<String, List<Employee1>>> entry : entries) {
System.out.println(entry.getValue());
}
}
//分组
@Test
public void test6() {
Map<Employee1.Status, List<Employee1>> map = employees.stream()
.collect(Collectors.groupingBy(Employee1::getStatus));
Set<Map.Entry<Employee1.Status, List<Employee1>>> entrySet = map.entrySet();
for (Map.Entry<Employee1.Status, List<Employee1>> statusListEntry : entrySet) {
System.out.println(statusListEntry.getValue());
}
}
@Test
public void test5() {
//总数
Long count = employees.stream()
.collect(Collectors.counting());
System.out.println(count);
System.out.println("-------------------");
//平均值
Double avg = employees.stream()
.collect(Collectors.averagingDouble(Employee1::getSalary));
System.out.println(avg);
//总和
Double sum = employees.stream()
.collect(Collectors.summingDouble(Employee1::getSalary));
System.out.println(sum);
//最大值
Optional<Employee1> max = employees.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(max.get());
//最小值
// Optional min = employees.stream()
// .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
// System.out.println(min.get());
Optional<Double> min = employees.stream()
.map(Employee1::getSalary)
.collect(Collectors.minBy(Double::compare));
System.out.println(min.get());
}
@Test
public void test4() {
List<String> list = employees.stream()
.map(Employee1::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("-----------------");
Set<String> list2 = employees.stream()
.map(Employee1::getName)
.collect(Collectors.toSet());
list2.forEach(System.out::println);
HashSet<String> hs = employees.stream()
.map(Employee1::getName)
.collect(Collectors.toCollection(HashSet::new));
hs.forEach(System.out::println);
}