5.6 付诸实践
在本节中,你会将迄今学到的关于流的知识付诸实践。我们来看一个不同的领域:执行交易的交易员。你的经理让你为八个查询找到答案。你能做到吗?5.6.2节会给出答案,但你应该自己先尝试一下作为练习。
(1) 找出2011年发生的所有交易,并按交易额排序(从低到高)。
(2) 交易员都在哪些不同的城市工作过?
(3) 查找所有来自于剑桥的交易员,并按姓名排序。
(4) 返回所有交易员的姓名字符串,按字母顺序排序。
(5) 有没有交易员是在米兰工作的?
(6) 打印生活在剑桥的交易员的所有交易额。
(7) 所有交易中,最高的交易额是多少?
(8) 找到交易额最小的交易。
5.6.1 领域:交易员和交易
以下是你要处理的领域,一个Traders和Transactions的列表:
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));
Trader和Transaction类的定义如下:
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 getName(){return this.name;}public String getCity(){return this.city;}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.trader = trader;this.year = year;this.value = value;}public Trader getTrader(){return this.trader;}public int getYear(){return this.year;}public int getValue(){return this.value;}public String toString(){return "{" + this.trader + ", " +"year: "+this.year+", " +"value:" + this.value +"}";}}
5.6.2 解答
解答在下面的代码清单中。你可以看看你对迄今所学知识的理解程度如何。干得不错!
代码清单 5-1 找出2011年发生的所有交易,并按交易额排序(从低到高)
List<Transaction> tr2011 =transactions.stream().filter(transaction -> transaction.getYear() == 2011) ←---- 给filter传递一个谓词来选择2011年的交易.sorted(comparing(Transaction::getValue)) ←---- 按照交易额进行排序.collect(toList()); ←---- 将生成的Stream中的所有元素收集到一个List中
代码清单 5-2 交易员都在哪些不同的城市工作过
List<String> cities =transactions.stream().map(transaction -> transaction.getTrader().getCity()) ←---- 提取与交易相关的每位交易员的所在城市.distinct() ←---- 只选择互不相同的城市.collect(toList());
这里还有一个新招:你可以去掉distinct(),改用toSet(),这样就会把流转换为集合。你在第6章中会了解到更多相关内容。
Set<String> cities =transactions.stream().map(transaction -> transaction.getTrader().getCity()).collect(toSet());
代码清单 5-3 查找所有来自于剑桥的交易员,并按姓名排序
List<Trader> traders =transactions.stream().map(Transaction::getTrader) ←---- 从交易中提取所有交易员.filter(trader -> trader.getCity().equals("Cambridge")) ←---- 仅选择位于剑桥的交易员.distinct() ←---- 确保没有任何重复.sorted(comparing(Trader::getName)) ←---- 对生成的交易员流按照姓名进行排序.collect(toList());
代码清单 5-4 返回所有交易员的姓名字符串,按字母顺序排序
String traderStr =transactions.stream().map(transaction -> transaction.getTrader().getName()) ←---- 提取所有交易员姓名,生成一个Strings构成的Stream.distinct() ←---- 只选择不相同的姓名.sorted() ←---- 对姓名按字母顺序排序.reduce("", (n1, n2) -> n1 + n2); ←---- 逐个拼接每个名字,得到一个将所有名字连接起来的String
请注意,此解决方案效率不高(所有字符串都被反复连接,每次迭代的时候都要建立一个新的String对象)。下一章中,你将看到一个更为高效的解决方案,它像下面这样使用joining(其内部会用到StringBuilder):
String traderStr =transactions.stream().map(transaction -> transaction.getTrader().getName()).distinct().sorted().collect(joining());
代码清单 5-5 有没有交易员是在米兰工作的
boolean milanBased =transactions.stream().anyMatch(transaction -> transaction.getTrader().getCity().equals("Milan")); ←---- 把一个谓词传递给anyMatch,检查是否有交易员在米兰工作
代码清单 5-6 打印生活在剑桥的交易员的所有交易额
transactions.stream().filter(t -> "Cambridge".equals(t.getTrader().getCity())) ←---- 选择住在剑桥的交易员所进行的交易.map(Transaction::getValue) ←---- 提取这些交易的交易额.forEach(System.out::println); ←---- 打印每个值
代码清单 5-7 所有交易中,最高的交易额是多少
Optional<Integer> highestValue =transactions.stream().map(Transaction::getValue) ←---- 提取每项交易的交易额.reduce(Integer::max); ←---- 计算生成的流中的最大值
代码清单 5-8 找到交易额最小的交易
Optional<Transaction> smallestTransaction =transactions.stream().reduce((t1, t2) ->t1.getValue() < t2.getValue() ? t1 : t2); ←---- 通过反复比较每个交易的交易额,找出最小的交易
你还可以做得更好。流支持min和max方法,它们可以接受一个Comparator作为参数,指定计算最小或最大值时要比较哪个键值:
Optional<Transaction> smallestTransaction =transactions.stream().min(comparing(Transaction::getValue));
