在实际开发中常常须要获取各类各样不一样格式的数据,由于数据库的表结构是一开始就设计好的因此不少时候咱们不得不先从数据库里或其余地方得到数据后再根据需求去一层一层的筛选数据,在Java 8以前的作法不外乎就是各类List、Set一块儿上,各类循环判断。若是只是简单的需求还好说,循环个一两次再判断一下就能够解决,可是需求复杂的话就会写出很复杂的代码出来,时间久了后不只本身看不懂,并且由于代码太复杂测试的时候不敢保证覆盖到全部的地方,万一代码到了线上出问题,不只很差改还可能影响到之前的功能,而在Java 8中就提供了新的特性stream,专门用于对集合中的数据进行筛选、分类等操做,下面咱们就会介绍stream的使用。java
咱们来看下面这段代码,Dish里面有一个属性calories
表明菜品的卡路里值,如今的需求是按卡路里对菜品进行排序再返回菜名,而且要求卡路里的值大于400。咱们能够看到下面的操做很是繁琐,先筛选出卡路里大于400的放入集合中,而后对这个集合进行排序,最后循环这个集合把名字放入一个新的集合,这是一个很常见的代码,在Java 8以前都是这么写的,可是这还只是对一个属性的筛选、排序就这么繁琐了,若是是多个属性会更加麻烦,下面咱们就看看用stream是怎么实现的。数据库
//将卡路里低于400的对象都放到集合中 List<Dish> lowCaloricDishes = new ArrayList<>(); for(Dish d: menu){ if(d.getCalories() < 400){ lowCaloricDishes.add(d); } } //把这个集合排序 Collections.sort(lowCaloricDishes, new Comparator<Dish>() { public int compare(Dish d1, Dish d2){ return Integer.compare(d1.getCalories(), d2.getCalories()); } }); //再新建一个String类型的集合来存放菜名 List<String> lowCaloricDishesName = new ArrayList<>(); for(Dish d: lowCaloricDishes){ lowCaloricDishesName.add(d.getName()); }
这是Java 8中stream的用法,咱们会发现这段代码写起来很是舒服,首先调用stream()
方法获取了集合menu
的流,而后调用了filter
方法来筛选出卡路里超过400的元素,接着调用了sorted
方法对筛选出来的元素进行排序,再调用map
方法把筛选出来的元素里面的name
属性抽出来做为一个新的流,最后一步则是调用collect
方法把存放name
的流转为List
格式返回,获得的结果和上面如出一辙,可是整个步骤一目了然,先作什么后作什么,很是清晰,这就是stream的用法。测试
import static java.util.Comparator.comparing; import static java.util.stream.Collectors.toList; List<Dish> menu = ... List<String> lowCaloricDishesName = menu.stream() //筛选出卡路里大于400的 .filter(d -> d.getCalories() < 400) //按卡路里值排序 .sorted(comparing(Dish::getCalories)) //抽取名字属性建立一个新的流 .map(Dish::getName) //这个流按List类型返回 .collect(toList());
讲到这里你们可能会产生疑惑,流究竟是什么,为何它能够进行这样的操做。简单来讲流其实就是 “从支持数据处理操做的源生成的元素序列” ,这句话究竟是什么意思呢?下面咱们来看看流的各类特性就明白了。spa
咱们来看下面的这段代码和它的流程图。它一开始从menu
这个集合中获取到了流,流里面的数据和集合是相同的,而后调用filter
方法以后筛选出符合条件的元素组成一个新的流传递给了map
方法,而后map
方法又从这个流里面把元素的名字取出来组成一个新流传递给limit
方法,limit
方法则只取了前3个组成一个流传递给collect
方法而后返回一个List
,这就是流的工做原理设计
List<String> list = menu.stream() //筛选出卡路里高于300的元素 .filter(d -> d.getCalories() > 300) //获取名字组成的流 .map(Dish::getName) //只取前3个 .limit(3) //返回List格式 .collect(toList()); System.out.println(list );
流和集合不同,集合能够想遍历多少次就遍历多少次,可是流只能遍历一次,若是你作了下面这样的操做,那代码会抛出一个java.lang.IllegalStateException
异常,流已被操做或关闭。3d
List<String> title = Arrays.asList("Java8", "In", "Action"); Stream<String> s = title.stream(); s.forEach(System.out::println); s.forEach(System.out::println);
仍是继续看这段代码,其中filter
、map
和limit
操做被称为 中间操做 , 中间操做 会返回一个新的流,而collect
则被称为 终端操做 ,只有终端操做才会让整个流执行并关闭,也就是说只有当collect
被执行时filter
、map
和limit
才会被执行,上面讲到流只能遍历一次就是由于forEach
就是一个终端操做,执行完后就关闭流了。code
List<String> list = menu.stream() //筛选出卡路里高于300的元素 .filter(d -> d.getCalories() > 300) //获取名字组成的流 .map(Dish::getName) //只取前3个 .limit(3) //返回List格式 .collect(toList());
以上就是stream的基本使用方法了,固然它的功能还远远不止这些,后面咱们还会讲到筛选、分组、查找等更强大的操做。对象