流的简介
简短的定义:从支持数据处理操作的源生成的元素序列
剖析这个定义
元素序列:像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值,因为集合是数据结构,所以他的主要目的是以特定的时间/空间复杂度存储和访问元素,但流的目的在于表达计算。集合讲的是数据,流讲的是计算。
源:流会使用一个提供数据的源,如集合、数组或输入/输出资源。请注意,从有序集合生成流时会保留原有的顺序。由列表生成的流,其元素序列与列表一致。
数据处理操作:流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中的常用操作,如filter、map、reduce、find、match、sort等。流操作可以顺序执行也可以并发执行。
流水线:很多流操作本身会返回一个流,这样多个操作就可以链接起来,形成一个流水线。
内部迭代:与使用迭代器显示迭代的集合不同,流的迭代操作是在背后进行的。
java8 Stream(流)常见的操作主要有以下几个方面
1)过滤筛选:filter
stream 接口支持filter方法,该操作接收一个谓词Predicate(一个返回bollean的函数)作为参数,并返回一个所有符合谓词元素的流。
2)排序:sort
3)去重:distinct
4)映射:map
map方法,它会接收一个函数作为参数,这个函数会被应用到每个元素上,并将其映射成一个新的元素。
5)查找匹配:anyMatch、allMatch、noneMatch、findFirst、findAny
anyMatch:流中是否有一个元素能匹配给定的谓词。
allMath:流中所有元素是否能匹配给定的谓词。
noneMath:可以确保流中没有任何元素与给定的谓词匹配。
findAny:返回当前流中的任意元素。
findFirst:返回流中的第一个元素。
findAny 和 findFirst 有什么区别?
答案是并行,找到一个元素在并行上限制有很多,如果不关心返回的那个元素,请使用findAny,因为它在使用并行流时限制很少。
6)归约和汇总:reduce、groupingBy
reduce:接收两个参数,归约函数
1)一个初始值,
2)一个 BinaryOperator<T> 来将两个元素结合起来产生一个新值,
求和用lambda (a,b) ->a+b
求积用lambda (a,b) ->a*b
groupingBy:对流按照元素进行分组
Map<Currency,List<Transaction>> transactionByCurrencies =
transactions.stream().collect(
groupingBy
(Transaction::getCurrency));
7)截短流
流支持limit(n),该方法返回一个不超过给定长度的流,所需长度作为常数传递给limit。如果流是有序的,则最多返回前n个元素。请注意,limit也可以用在无序流上,比如源是一个set,这种情况,limit的结果不会以任何顺序排列。
8)跳过元素
流支持ship(n)方法,返回一个扔掉前n个元素的流,如果流中元素不足n个,怎返回一个空流,注意 limit 和 ship 是互补的。
9)流的扁平化(稍后会有专门的一篇文章来讲解流的扁平化)
flatMap方法,可以将生成的单个流合并起来,即扁平化一个流。
几种类型的实际应用案例(以下几个案例是比较常见的stream操作,认真琢磨思考)
案例:
执行交易的交易员。你的经理让你为八个查询找到答案
1)找出2011年发生的所有交易,并且按照交易额排序(从低到高) 2)交易员都在哪些不同城市工作过 3)查找所有来自于剑桥的交易员,并且按照姓名排序 4)返回所有交易员的姓名字符串,按字母排序 5)有没有交易员是在米兰工作过? 6)打印生活在剑桥的交易员所有交易额。 7)所有交易中,最高的交易额是多少? 8)找到交易额的最小的交易。
代码实现
实体类创建:
//交易员
public class Trader { private final String name; private final String city; public Trader(String n, String c) { this.name = n; this.city = c; } public String getCity() { return city; } public String getName() { return name; } public String toString(){ return "{"+"Trader:"+this.name+"in " + this.city; } }
实体类创建:
//交易信息类
public class Transaction { private final Trader trader; private final int year; private final int value; public Transaction(Trader trader, int year, int value){ this.value = value; this.year = year; this.trader = trader; } public Trader getTrader(){ return this.trader; } public int getValue() { return value; } public int getYear() { return year; } public String toString(){ return "{"+this.trader+","+"year:"+this.year+","+"value:"+this.value+"}"; } }
八种查询实现
/*测试用例:执行交易的交易员。你的经理让你为八个查询找到答案 1)找出2011年发生的所有交易,并且按照交易额排序(从低到高) 2)交易员都在哪些不同城市工作过 3)查找所有来自于剑桥的交易员,并且按照姓名排序 4)返回所有交易员的姓名字符串,按字母排序 5)有没有交易员是在米兰工作过? 6)打印生活在剑桥的交易员所有交易额。 7)所有交易中,最高的交易额是多少? 8)找到交易额的最小的交易。 * */ public class learnStream { public static void main(String arg[]){ Trader raoul = new Trader("Raoul","Cambridge"); Trader mario = new Trader("Mario","Milan"); Trader alan = new Trader("Alan","Cambridge"); Trader brian = new Trader("Brian","Cambridge"); List<Transaction> transactions = Arrays.asList( new Transaction(brian,2011,300), new Transaction(raoul,2012,1000), new Transaction(raoul,2011,400), new Transaction(mario,2012,710), new Transaction(mario,2012,700), new Transaction(alan,2012,950) ); //1)找出2011年发生的所有交易,并且按照交易额排序(从低到高) List<Transaction> tr2011 = transactions.stream() .filter(transaction ->transaction.getYear() == 2011) .sorted(Comparator.comparing(Transaction::getValue)) .collect(toList()); //2)交易员都在哪些不同城市工作过 List<String> cities = transactions.stream() .map(transaction -> transaction.getTrader().getCity()) .distinct() .collect(toList()); //3)查找所有来自于剑桥的交易员,并且按照姓名排序 List<Trader> name = transactions.stream() .map(transaction -> transaction.getTrader()) .filter(trader -> trader.getCity().equals("Cambridge")) .distinct() .sorted(Comparator.comparing(Trader::getName)) .collect(toList()); //4)返回所有交易员的姓名字符串,按字母排序 String traderStr = transactions.stream() .map(transaction -> transaction.getTrader().getName()) .distinct() .sorted() .reduce("",(n1,n2) -> n1+n2); String traderStr2 = transactions.stream() .map(transaction -> transaction.getTrader().getName()) .distinct() .sorted() .collect(joining()); //5)有没有交易员是在米兰工作过? boolean mailanBased = transactions.stream() .anyMatch(transaction -> transaction.getTrader().getCity().equals("Milan")); //6)打印生活在剑桥的交易员所有交易额。 transactions.stream() .filter(transaction -> transaction.getTrader().getCity().equals("Cambridge")) .map(Transaction::getValue) .forEach(System.out::println); //7)所有交易中,最高的交易额是多少? Optional<Integer> highestValue = transactions.stream() .map(transaction -> transaction.getValue()) .reduce(Integer::max); //8)找到交易额的最小的交易。 Optional<Transaction> smallestTransaction = transactions.stream() .min(Comparator.comparing(Transaction::getValue)); } }