JAVA编程艺术之guava应用

xiaoxiao2021-02-28  44

数据处理函数编程之Guava

最近在开发宝贝化项目过程中,遇到一个问题:同一个车型对应多种价格,需要做过滤处理,保留统一车型最低的价格;看似很简单的问题,但如何优雅的编程,让代码更加简洁,性能更好。对于有代码洁癖的人来说,想到了guava强大的函数处理功能以及Jdk8 stream语法;项目结束之后,想把这个guava函数编程应用总结分享一下

guava的应用场景guava排序功能guava过滤功能jdk8的lambda表达式jdk8的Stream语法

guava的应用场景

前后端分离技术体系redux的应用场景有过这么一句话:当你不知道什么时候用到redux的时候,那就是不需要它。其实在java这种面向对象的编程思想,很少会考虑到函数式编程,主要在于函数式编程不符合面向对象的思想,难以理解,甚至有时候代码阅读非常困难,对于代码的维护那是一件灾难性的事件。所以一般场景不太建议大家用函数式编程。但有些场景比如复杂的数据处理,算法运算等等,这些可以考虑用到guava的函数编程思想。

排序功能

排序器Ordering是guava流畅风格排序器Comparator的模板实现,用它可以构建复杂的集合排序功能

《一》常见的排序器

方法功能natural()对排序类型自然排序:数字大小、日期先后顺序等usingToString()对字符串进行字典排序arbitrary()无序,每次排序的结果都不相同

实现自定义排序器,通常可以使用Ordering.from(Comparator)的方式,或者实现Ordering模板构造

Comparator<String> vr = (s1, s2) -> BigDecimal.valueOf(Double.valueOf(s1)).compareTo(BigDecimal.valueOf(Double.valueOf(s2))); TreeMultimap<Long, String> keyMap = TreeMultimap.create(Ordering.natural(), Ordering.from(vr));

示例:

List<String> tlist = Lists.newArrayList(ImmutableList.of("welcome","to","guava","java","lambda")); System.out.println("排序前:" + JSON.toJSONString(tlist)); //排序前:["welcome","to","guava","java","lambda"] tlist = Ordering.usingToString().sortedCopy(tlist); System.out.println("排序后" + JSON.toJSONString(tlist)); //排序后["guava","java","lambda","to","welcome"]

《二》链式调用方法:通过链式调用,可以由给定的排序器衍生出其它排序器

方法功能reverse()获取语义相反的排序器nullsFirst()把null值排在最前面nullsLast()把null值排在最后面compound(Comparator)合成另一个比较器,以处理当前排序器中的相等情况onResultOf(Function)对集合中元素调用Function,再按返回值用当前排序器排序

示例:

对PriceInfo这个类,对车型carType自然排序,null值排在前面(纯属为了说明用法)

@Data public class PriceInfo { /** * 车型 */ private Long carType; /** * 价格 */ private String price; }

实现方式:

Function<PriceInfo, Long> sortCarTypeFunction = new Function<PriceInfo, Long>() { @Override public Long apply(PriceInfo priceInfo) { return priceInfo.getCarType(); } }; Ordering<PriceInfo> carTypeOrdering = Ordering.natural().reverse().nullsFirst().onResultOf(sortCarTypeFunction);

过滤功能

我们可以使用com.google.common.collect.Iterables和com.google.common.base.Predicates类来过滤例子中的列表

List<String> filterList = Lists.newArrayList("welcome", "to", "guava", "java", "lambda"); Predicate<String> lessThenPredicate = new Predicate<String>() { @Override public boolean apply(String s) { return s.length() > 5; } }; Iterable<String> filterResult = Iterables.filter(filterList, Predicates.or((Predicates.or(Predicates.equalTo("guava"), Predicates.equalTo("java"))), lessThenPredicate)); Preconditions.checkArgument(Lists.newArrayList(filterResult).containsAll(Lists.newArrayList("guava", "java", "to")), "集合包含:[guava,welcome,lambda,java]");

Jdk8的Stream语法以及Lambda表达式应用

API地址:https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

jdk8引入stream语法主要是为了弥补函数式编程的缺陷,实际上也是借鉴了guava的函数编程风格;stream和I/O不同,它更像具有Iterable的集合类,但行为和集合类又有所不同。整体来讲Stream API包含构建、中间操作、终端操作;

《一》Stream构建

使用Stream静态方法来创建Stream:主要有of、generator、iterate方法通过Collection子类获取Stream

《二》Stream的中间操作

filter: 对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素;map: 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。之所以会有这样三个变种方法,可以免除自动装箱/拆箱的额外消耗;limit: 对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素;

《三》Stream的终端操作

collect:可变汇聚方法: List<PriceInfo> result = list.stream().filter(priceInfo -> { Long carType = priceInfo.getCarType(); if (null != keyMap.get(carType) && keyMap.get(carType).size() > 1) { return keyMap.get(carType).first().equals(priceInfo.getPrice()); } return true; }).collect(Collectors.toList()); reduce操作:比如count、sum等函数

附:对同一个车型进行过滤,保留最低价格,代码示例:

PriceInfo p1 = new PriceInfo(); p1.setCarType(2L); p1.setPrice("23"); PriceInfo p2 = new PriceInfo(); p2.setCarType(3L); p2.setPrice("20"); PriceInfo p3 = new PriceInfo(); p3.setCarType(2L); p3.setPrice("19"); PriceInfo p4 = new PriceInfo(); p4.setCarType(2L); p4.setPrice("30"); List<PriceInfo> list = Lists.newArrayList(ImmutableList.of(p1, p2, p3, p4)); Comparator<String> vr = (s1, s2) -> BigDecimal.valueOf(Double.valueOf(s1)).compareTo(BigDecimal.valueOf(Double.valueOf(s2))); TreeMultimap<Long, String> keyMap = TreeMultimap.create(Ordering.natural(), Ordering.from(vr)); list.stream().forEach(priceInfo -> { keyMap.put(priceInfo.getCarType(), priceInfo.getPrice()); }); List<PriceInfo> result = list.stream().filter(priceInfo -> { Long carType = priceInfo.getCarType(); if (null != keyMap.get(carType) && keyMap.get(carType).size() > 1) { return keyMap.get(carType).first().equals(priceInfo.getPrice()); } return true; }).collect(Collectors.toList());

更多Stream功能了解:https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

转载请注明原文地址: https://www.6miu.com/read-2629591.html

最新回复(0)