java8中有两大最为重要的改变。一个是Lambda表达式,另一个是Stream API。
Stream 中文称为 “流”,通过将集合转换为这么一种叫做 “流” 的元素序列,通过声明性方式,能够对集合中的每个元素进行一系列并行或串行的流水线操作。Stream API提供了一种高效且易于使用的处理数据的方式。
先说下Stream的优势:Collection是一种静态的内存数据结构,面向内存存储在内存中,而Stream是有关计算的,面向CPU通过CPU实现计算的。它是java对集合操作的优化,相较于迭代器,使用Stream的速度非常快,并且它支持并行方式处理集合中的数据,默认情况能充分利用cpu的资源。同时支持函数式编程,代码非常简洁。
注意:
stream自己不会存储元素;
Stream不会改变源对象。相反,它会返回一个持有结果的新Stream;
Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream的操作三步骤
1.创建stream
Stream的创建需要一个数据源(通常是一个容器或者数组):
@Test public void test1(){ //方法一、通过集合创建stream List<String> list= Arrays.asList("aa","dd","cc","bb","mm","zz"); //返回一个顺序流 Stream<String> stream1 = list.stream(); //返回一个并行流 Stream<String> stringStream1 = list.parallelStream(); //方法二、通过数组创建stream int[] array={1,2,3,4,5}; IntStream stream2 = Arrays.stream(array); //方法三、通过stream类中的静态方法of创建 Stream<String> stream3 = Stream.of("I", "love", "you", "too"); //方法四、创建无限流 //迭代,遍历前十个偶数 Stream<Integer> stream4 = Stream.iterate(0, t -> t + 2); stream4.limit(10).forEach(System.out::println); //生成 Stream.generate(Math::random).limit(10).forEach(System.out::println); }
2.中间操作
多个中间操作可以连成一条流水线,除非流水线触发终止操作,不然中间操作不会执行任何的处理,属于延迟加载。
中间操作就是对容器的处理过程,包括:排序(sorted...),筛选(filter,limit,distinct...),映射(map,flatMap...)等
2.1 筛选与切片
filter(Predicate<? super T> predicate):从流中过滤某些元素
limit(long maxSize):截断流
skip(n):跳过前n个元素,与limit配合使用实现分页操作
distinct:去重,使用了hashCode和equals方法来获取不同的元素,因此我们的类必须实现hashCode和equals方法。
@Test public void test2(){ User user1=new User("1003","张三",25,"成都"); User user2=new User("1004","李四",22,"绵阳"); User user3=new User("1002","王五",24,"南充"); User user4=new User("1005","赵六",23,"广元"); User user5=new User("1001","张三",21,"成都"); User user6=new User("1003","张三",25,"南充"); User user7=new User("1004","李四",22,"绵阳"); User user8=new User("1003","张三",25,"成都"); List<User> list=Arrays.asList(user1,user2,user3,user4,user5,user6,user7,user8); //filter过滤 list.stream().filter(u->u.getAge()>=24).forEach(System.out::println); System.out.println("******************"); //limit截断 list.stream().filter(u->"张三".equals(u.getName())).limit(2).forEach(System.out::println); System.out.println("******************"); //skip list.stream().skip(2).limit(5).forEach(System.out::println); System.out.println("******************"); //skip,User类需实现hashCode与equals方法 list.stream().filter(u->"张三".equals(u.getName())).distinct().forEach(System.out::println); }
2.2 映射
map(function f):接收一个函数作为参数,将元素转换为其他形式或提取信息,该函数会被应用到每一个元素上,并将其映射为一个新的元素。
flatMap(function f):接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
@Test public void test3(){ //map(function f) List<String> list= Arrays.asList("aa","dd","cc","bb","mm","zz"); list.stream().map(str->str.toUpperCase()).forEach(System.out::println); System.out.println("***********"); User user1=new User("1003","张三",25,"成都"); User user2=new User("1004","李四",22,"绵阳"); User user3=new User("1002","王五",24,"南充"); List<User> list2=Arrays.asList(user1,user2,user3); list2.stream().map(User::getName).forEach(System.out::println); //flushMap(function f) System.out.println("*********"); list.stream().flatMap(StreamTest::filterCharactor).forEach(System.out::println); } public static Stream<Character> filterCharactor(String str){ List<Character> list=new ArrayList<>(); for(Character ch:str.toCharArray()){ list.add(ch); } return list.stream(); }
2.3 排序
sorted():自然排序,其中的元素必须实现Comparable接口;
sorted(Comparator com):定制排序,我们可以使用lambda来创建一个Comparator实例,可以按照升序或者降序来排序元素。
@Test public void test4(){ //sorted():自然排序:Comparable List<String> list= Arrays.asList("aa","dd","cc","bb","mm","zz"); list.stream().sorted().forEach(System.out::println); System.out.println("**************"); //sorted(Comparator com) --定制排序 User user1=new User("1001","张三",25,"南充"); User user2=new User("1002","李四",22,"绵阳"); User user3=new User("1003","王五",25,"成都"); User user4=new User("1004","赵六",21,"乐山"); User user5=new User("1005","田七",22,"南充"); List<User> list2=Arrays.asList(user1,user2,user3,user4,user5); list2.stream().sorted((u1,u2)->{ if(u1.getAge().equals(u2.getAge())){ return u1.getName().compareTo(u2.getName()); }else{ return -u1.getAge().compareTo(u2.getAge()); } }).forEach(System.out::println); }
3.终止操作
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
3.1查找与匹配
allMatch 检查是否匹配所有元素
anyMatch 检查是否至少匹配一个元素
noneMatch 检查是否没有匹配所有元素
findFirst 返回第一个元素
findAny 返回当前流中的任意元素
count 返回流中元素的总个数
max 返回流中最大值
min 返回流中最小值
@Test public void test5(){ User user1=new User("1001","张三",26,"南充"); User user2=new User("1002","李四",22,"绵阳"); User user3=new User("1003","王五",25,"成都"); User user4=new User("1004","赵六",21,"乐山"); User user5=new User("1005","田七",22,"南充"); List<User> list1=Arrays.asList(user1,user2,user3,user4,user5); //allMatch boolean b1 = list1.stream().allMatch(u -> u.getAge() == 22); System.out.println("allMatch==="+b1); //anyMatch boolean b2 = list1.stream().anyMatch(u -> u.getAge() == 22); System.out.println("anyMatch==="+b2); //noneMatch boolean b3 = list1.stream().noneMatch(u -> u.getAge() == 22); System.out.println("noneMatch==="+b3); //findFirst Optional<User> first = list1.stream().sorted((u1, u2) -> Integer.compare(u1.getAge(), u2.getAge())).findFirst(); System.out.println(first.get()); //findAny System.out.println("-------------------"); Optional<User> any = list1.stream().findAny(); System.out.println(any.get()); //count long count = list1.stream().count(); System.out.println("count==="+count); //max Optional<User> max = list1.stream().max((u1, u2) -> Integer.compare(u1.getAge(), u2.getAge())); System.out.println(max.get()); //min Optional<Integer> min = list1.stream().map(User::getAge).min(Integer::compare); System.out.println(min.get()); }
3.2 归约
reduce(T identity,BinaryOperator):可以将流中元素反复结合起来,得到一个值。返回T
reduce(BinaryOperator):返回Optional<T>
@Test public void test6(){ //reduce(T t,BinaryOperator b) List<Integer> list1=Arrays.asList(1,2,3,4,5,6,7,8,9,10); Integer sum = list1.stream().reduce(0, (x, y) -> x + y); System.out.println("sum="+sum); //reduce(BinaryOperator b) User user1=new User("1001","张三",26,"南充"); User user2=new User("1002","李四",22,"绵阳"); User user3=new User("1003","王五",25,"成都"); User user4=new User("1004","赵六",21,"乐山"); User user5=new User("1005","田七",22,"南充"); List<User> list2= Arrays.asList(user1,user2,user3,user4,user5); Optional<Integer> sumAge = list2.stream().map(u -> u.getAge()).reduce(Integer::sum); System.out.println("sumAge="+sumAge.get()); }
3.3 收集
collect(Collector c):将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。
Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、set、map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例。
@Test public void test7(){ User user1=new User("1001","张三",26,"南充"); User user2=new User("1002","李四",22,"成都"); User user3=new User("1003","王五",25,"成都"); User user4=new User("1004","赵六",21,"乐山"); User user5=new User("1005","张三",22,"南充"); List<User> list1= Arrays.asList(user1,user2,user3,user4,user5); //收集list List<String> list = list1.stream().map(u -> u.getName()).collect(Collectors.toList()); list.forEach(System.out::println); System.out.println("---------------------"); //收集set Set<String> set = list1.stream().map(u -> u.getName()).collect(Collectors.toSet()); set.forEach(System.out::println); System.out.println("---------------------"); //收集平均值 Double avg = list1.stream().collect(Collectors.averagingInt(User::getAge)); System.out.println("avg="+avg); System.out.println("----------------"); //收集sum int sum = list1.stream().collect(Collectors.summingInt(User::getAge)); System.out.println("sum="+sum); System.out.println("----------------"); //收集max Optional<User> maxUser = list1.stream().collect(Collectors.maxBy((u1, u2) -> Integer.compare(u1.getAge(), u2.getAge()))); System.out.println(maxUser); System.out.println("----------------"); //收集min Optional<Integer> min = list1.stream().map(User::getAge).collect(Collectors.minBy(Integer::compare)); System.out.println(min.get()); System.out.println("----------------"); //分组 Map<String, List<User>> groupUser = list1.stream().collect(Collectors.groupingBy(User::getAddress)); System.out.println(groupUser); System.out.println("----------------"); //分区 Map<Boolean, List<User>> partMap = list1.stream().collect(Collectors.partitioningBy(u -> u.getAge() > 24)); System.out.println(partMap); System.out.println("----------------"); //连接字符串 String str = list1.stream().map(User::getName).collect(Collectors.joining(",")); System.out.println(str); }