目录
Java8中有两大最为重要的改变:
- Lambda 表达式;
- Stream API(java.util.stream.*);
Steam是对集合 (Collection) 对象功能的增强, 它可以执行非常复杂的查找、过滤和映射数据等操作。Stream将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选,排序,聚合等。元素流在管道中经过中间操作(intermediateoperation)的处理,最后由最终操作(terminaloperation)得到前面处理的结果。
简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
Stream 自己不会存储元素。
Stream 不会改变源对象。他们会返回一个持有结果的新Stream。
Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
1、创建Stream
1.1 通过集合创建流
Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
- default Stream<E> stream() : 返回一个顺序流
- default Stream<E> parallelStream() : 返回一个并行流
public class StreamExample01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
Stream<String> stringStream = list.parallelStream();
}
}
1.2 由数组创建流
Java8 中的 Arrays 的静态方法 stream() 可 以获取数组流:
- static <T> Stream<T> stream(T[] array): 返回一个流
重载形式,能够处理对应基本类型的数组:
- public static IntStream stream(int[] array)
- public static LongStream stream(long[] array)
- public static DoubleStream stream(double[] array)
public class StreamExample02 {
public static void main(String[] args) {
String[] strArray = new String[10];
Stream<String> stream = Arrays.stream(strArray);
}
}
1.3 由值创建流
可以使用静态方法 Stream.of(), 通过显示值 创建一个流。它可以接收任意数量的参数。
- public static<T> Stream<T> of(T... values) : 返回一个流
public class StreamExample03 {
public static void main(String[] args) {
Stream<String> stream = Stream.of("a", "b", "c");
stream.forEach(System.out::println);
}
}
1.4 由函数创建流
可以使用静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。
1.4.1 迭代
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
public class StreamExample04 {
public static void main(String[] args) {
int seed = 0;
Stream<Integer> iterate = Stream.iterate(seed, x -> x + 2);
iterate.limit(10).forEach(System.out::println);
}
}
1.4.2 生成
public static<T> Stream<T> generate(Supplier<T> s) :
public class StreamExample05 {
public static void main(String[] args) {
Stream<Integer> generate = Stream.generate(() -> (int)(Math.random()*100));
generate.limit(10).forEach(System.out::println);
}
}
2、中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理! 而在终止操作时一次性全部处理,称为“惰性求值”。
2.1 筛选与切片
方法 | 描 述 |
filter(Predicate p) | 接收 Lambda , 从流中排除某些元素。 |
distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去 除重复元素。 |
limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素 不足 n 个,则返回一个空流。与 limit(n) 互补。 |
public class StreamExample06 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(55, 19, 36, 55, 9, 66, 23, 99, 11);
list.stream().filter((e) -> e > 30).forEach(System.out::println);
}
}
public class StreamExample07 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(55, 19, 36, 55, 9, 66, 23, 99, 11);
list.stream()
.filter((e) -> e > 30)
.distinct()
.limit(3)
.forEach(System.out::println);
}
}
如下下面代码,中间操作,没有执行任何处理,执行终止操作forEach时,执行中间操作。
public class StreamExample08 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(10,19,36,50,9,66);
Stream<Integer> stream = list.stream()
.filter((e) -> {
System.out.println("Stream中间操作");
return e > 50;
});
// 终止操作
System.out.println("Stream终止操作");
stream.forEach(System.out::println);
}
}
运行结果:
Stream终止操作
Stream中间操作
Stream中间操作
Stream中间操作
Stream中间操作
Stream中间操作
Stream中间操作
66
2.2 映射
方法 | 描 述 |
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素。 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 DoubleStream。 |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 IntStream。 |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 LongStream。 |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流。 |
public class StreamExample09 {
static List<Employee> employees = Arrays.asList(
new Employee(1,"zhang",36),
new Employee(2,"wang",23),
new Employee(3,"li",18),
new Employee(4,"zhao",29),
new Employee(5,"zhou",26)
);
public static void main(String[] args) {
List<String> list = Arrays.asList("aa","bb","cc","dd","ee");
list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
employees.stream().map(Employee::getName).forEach(System.out::println);
}
}
class Employee{
int id;
String name;
int age;
public Employee() {
}
public Employee(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
}
2.3 排序
方法 | 描 述 |
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
public class StreamExample10 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(10,19,36,50,9,66);
list.stream().sorted().forEach(System.out::println);
// 倒序排列
list.stream().sorted((x,y)-> Integer.compare(y,x)).forEach(System.out::println);
}
}
3、终止操作
终端操作会从流的流水线生成结果。其结果可以是任何不是流的 值,例如:List、Integer,甚至是 void 。
3.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 使用内部 迭代——它帮你把迭代做了) |
public class StreamExample11 {
public static void main(String[] args) {
List<String> list = Arrays.asList("A","B","C","D","A");
boolean allMatch = list.stream().allMatch(str -> str.equals("A"));
System.out.println(allMatch);
boolean anyMatch = list.stream().anyMatch(str -> str.equals("A"));
System.out.println(anyMatch);
boolean noneMatch = list.stream().noneMatch(str -> str.equals("A"));
System.out.println(noneMatch);
Optional<String> first = list.stream().findFirst();
System.out.println(first.get());
Optional<String> findAny = list.stream().findAny();
System.out.println(findAny.get());
long count = list.stream().count();
System.out.println(count);
Optional<String> max = list.stream().max(String::compareTo);
System.out.println(max.get());
Optional<String> min = list.stream().min(String::compareTo);
System.out.println(min.get());
}
}
3.2 归约
方法 | 描 述 |
reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。 返回 T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。 返回 Optional<T> |
public class StreamExample12 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(10,19,36,50,9,66);
Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(reduce);
Optional<Integer> optional = list.stream().reduce(Integer::sum);
System.out.println(optional.get());
}
}
public class StreamExample13 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(10,19,36,50,9,66,19);
List<Integer> collect = list.stream().collect(Collectors.toList());
System.out.println(collect);
Set<Integer> set = list.stream().collect(Collectors.toSet());
System.out.println(set);
HashSet<Integer> hashSet = list.stream().collect(Collectors.toCollection(HashSet::new));
System.out.println(hashSet);
Long counting = list.stream().collect(Collectors.counting());
System.out.println(counting);
Double averagingInt = list.stream().collect(Collectors.averagingInt(e -> e));
System.out.println(averagingInt);
Integer summingInt = list.stream().collect(Collectors.summingInt(e -> e));
System.out.println(summingInt);
Optional<Integer> maxBy = list.stream().collect(Collectors.maxBy(Integer::compare));
System.out.println(maxBy.get());
Optional<Integer> minBy = list.stream().collect(Collectors.minBy(Integer::compare));
System.out.println(minBy.get());
IntSummaryStatistics summarizingInt = list.stream().collect(Collectors.summarizingInt(e -> e));
System.out.println(summarizingInt.getCount());
System.out.println(summarizingInt.getAverage());
System.out.println(summarizingInt.getMax());
System.out.println(summarizingInt.getMin());
System.out.println(summarizingInt.getSum());
}
}
public class StreamExample14 {
static List<User> list = Arrays.asList(
new User(1,"zhang","开发"),
new User(2,"wang","开发"),
new User(3,"li","测试"),
new User(4,"zhao","运营"),
new User(5,"zhou","前端")
);
public static void main(String[] args) {
Map<String, List<User>> groupingBy = list.stream().collect(Collectors.groupingBy(User::getDept));
System.out.println(groupingBy);
Map<Boolean, List<User>> partitioningBy = list.stream().collect(Collectors.partitioningBy(x -> x.getDept().equals("开发")));
System.out.println(partitioningBy);
String joining1 = list.stream().map(User::getName).collect(Collectors.joining());
System.out.println(joining1);
String joining2 = list.stream().map(User::getName).collect(Collectors.joining(","));
System.out.println(joining2);
String joining3 = list.stream().map(User::getName).collect(Collectors.joining(",","[","]"));
System.out.println(joining3);
}
}
class User{
int id;
String name;
String dept;
......
// 构造方法 ,get ,set,toString省略
}