大概一年多之前,我对java8的理解还仅限一些只言片语的文章之上,后来出于对函数式编程的兴趣,买了本参考书看了一遍,然后放在了书架上,后来,当我接手大客户应用的开发工作之后,java8的一些工具,对我的效率有了不小的提升,因此想记录一下java"8的一些常用场景,我希望这会成为一个小字典,能让我免于频繁翻书,但是总能找到自己想找的知识。
用于举例的model:
@Data public class Apple { private Long appleId; private String appleName; private Float appleWeight; private Integer appleClassic; }一、Java 8 Lambda 表达式
这无疑是最常用的功能之一,其实lambda表达式的作用,应该就是简洁明了,实际上是用最短的字符,通过类型推导,语法糖等方式去对编译器描述清楚这段代码的功能,这和泛型有点相似,对于编程人员来说,一定程度上也提高了编程效率和代码可读性。
如常用的lambda表达式:
process(()->System.out.println("this is so cool!"))
例如对苹果重量排序:
Listapples = Lists.newArrayList(); for (int i = 1; i < 10; i++) { Apple apple = new Apple(); apples.add(apple); } apples.sort(Comparator.comparing(Apple::getAppleWeight)); 反序: apples.sort(Comparator.comparing(Apple::getAppleWeight).reversed()); 重量相同时:比较等级: apples.sort(Comparator .comparing(Apple::getAppleWeight) .reversed() 谓词复合查询: Predicate a = apple -> apple.getAppleWeight() > 10; weight10.or(apple -> apple.getAppleClassic() > 2) .and(apple -> StringUtils.equalsIgnoreCase(apple.getAppleName(), "优质苹果")); 可以看做(a||b)&&c 函数复合: Function f = a -> a.getAppleWeight() + 1; Function g = a -> a * 2; Function h = f.andThen(g); 数学写作 h=g(f(x)) Function g = a -> a.getAppleWeight() + 1; Function f = a -> a * 2; Function h = f.compose(g); 数学写作 h=f(g(x))
小结:java8实际上想传递函数,函数是什么?是一个映射,可以看做x->y,输入x然后映射到值y的过程,
java无法摆脱一切皆是对象的思想,因此函数式依附在对象上传递的,因此也有了下面的说法,方法引用,以及函数式接口,让函数随着对象传递,为了函数式编程,甚至专门写一个接口---对象来传递函数。然而,函数才是主角。
方法引用十分简单,其实也是将方法作为参数传递。使用::域作用符,将一段方法传递。
举例:Apple::getAppleId
String::subString System.out::println三、Java 8 函数式接口 函数式编程
利用java进行函数式编程主要就是利用函数式接口,但是函数式接口在java8之前就有一些了,就例如多线程的runnable,但是8以前是没有lambda表达式的,所以只能使用匿名内部类,在用过lambda表达式的人看来,那是相当臃肿的,8更新了lambda表达式,这就使函数式编程更上一层楼.
java8的函数式接口为我们传递函数提供了工具,我们可以自己定义函数式接口,然后让其他人,或者是java API调用。
关于函数接口,需要记住的就是两件事:
函数接口是行为的抽象;
函数接口是数据转换器。
在我接触到java8流式处理的时候,我的第一感觉是流式处理让集合操作变得简洁了许多,通常我们需要多行代码才能完成的操作,借助于流式处理可以在一行中实现。其本质是,将一些原本开发者需要做的处理如迭代等,放在了java库里,让我们只关心自己的业务逻辑,比如我们希望对一个包含整数的集合中筛选出所有的偶数,并将其封装成为一个新的List返回,那么在java8之前,我们需要通过如下代码实现:
过去: Listevens = new ArrayList<>(); for (final Integer num : nums) { if (num % 2 == 0) { evens.add(num); } } stream实现: List evens = nums.stream().filter(num -> num % 2 == 0).collect(Collectors.toList()); 我们需要取出10个等级高于3的苹果,跳过其中两个,按重量排序,去重,然后取出苹果的Name,然后取出名字的每个字符: List appleName = apples.parallelStream() .filter(a -> a.getAppleClassic() < 2) .sorted(Comparator.comparing(Apple::getAppleWeight)) .map(Apple::getAppleName) .map(s -> s.split("")) .limit(10) .skip(2) .distinct() .flatMap(Arrays::stream) .collect(Collectors.toList()); 构造AppleId ApppleName Map: Map appleIdMap = apples.stream() .collect(Collectors.toMap(Apple::getAppleId, Apple::getAppleName, (s, s2) -> s.length() > s2.length() ? s : s2)); 谓词查找: if (appleName.stream().anyMatch(a -> StringUtils.equalsIgnoreCase(a, "一级苹果"))); if (appleName.stream().allMatch(a -> StringUtils.equalsIgnoreCase(a, "一级苹果"))); if (appleName.stream().noneMatch(a -> StringUtils.equalsIgnoreCase(a, "一级苹果"))); 短路查找: appleName.stream() .filter(a -> StringUtils.equalsIgnoreCase(a, "一级苹果")) .findAny() .ifPresent(System.out::println); findfirst在并行时限制多一些,如果不在意返回的是哪个元素,使用findAny。 求和: apples.stream() .map(Apple::getAppleWeight) .reduce(0F, (a, b) -> a + b); 计数: apples.stream().count();
使用stream的好处:
1.更简洁,更易读
2.可复合,更灵活
3.可并行
Optional着重为解决java的NPE问题是Java8提供的为了解决null安全问题的一个API。善用Optional可以使我们代码中很多繁琐、丑陋的设计变得十分优雅。
使用Optional,我们就可以把下面这样的代码进行改写: public static String getName(User u) { if (u == null) return "Unknown"; return u.name; } 不过,千万不要改写成这副样子。 public static String getName(User u) { Optionaluser = Optional.ofNullable(u); if (!user.isPresent()) return "Unknown"; return user.get().name; } 这样才是正确使用Optional的姿势。那么按照这种思路,我们可以安心的进行链式调用,而不是一层层判断了。 public static String getName(User u) { return Optional.ofNullable(u) .map(user->user.name) .orElse("Unknown"); } 看一段代码: public static String getChampionName(Competition comp) throws IllegalArgumentException { if (comp != null) { CompResult result = comp.getResult(); if (result != null) { User champion = result.getChampion(); if (champion != null) { return champion.getName(); } } } throw new IllegalArgumentException("The value of param comp isn"t available."); } 让我们看看经过Optional加持过后,这些代码会变成什么样子。 public static String getChampionName(Competition comp) throws IllegalArgumentException { return Optional.ofNullable(comp) .map(c->c.getResult()) .map(r->r.getChampion()) .map(u->u.getName()) .orElseThrow(()->new IllegalArgumentException("The value of param comp isn"t available.")); } 还有很多不错的使用姿势,比如为空则不打印可以这么写: string.ifPresent(System.out::println);
参考资料:《Java 8 in Action: Lambdas, streams, and functional-style programming》 Raoul-gabriel Urma (作者), Mario Fusco (作者), Alan Mycroft (作者)
作者:文烁
点击 阅读更多 查看更多详情
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/73147.html
摘要:依旧使用刚刚对苹果排序的代码。现在,要做的是筛选出所有的绿苹果,也许你会这一个这样的方法在之前,基本上都是这样写的,看起来也没什么毛病。但是,现在又要筛选一下重量超过克的苹果。 《Java8实战》-读书笔记第一章(01) 最近一直想写点什么东西,却不知该怎么写,所以就写写关于看《Java8实战》的笔记吧。 第一章内容较多,因此打算分几篇文章来写。 为什么要关心Java8 自1996年J...
摘要:并发教程原子变量和原文译者飞龙协议欢迎阅读我的多线程编程系列教程的第三部分。如果你能够在多线程中同时且安全地执行某个操作,而不需要关键字或上一章中的锁,那么这个操作就是原子的。当多线程的更新比读取更频繁时,这个类通常比原子数值类性能更好。 Java 8 并发教程:原子变量和 ConcurrentMap 原文:Java 8 Concurrency Tutorial: Synchroni...
摘要:使用解决的数据流问题原文译者飞龙协议在年三月发布,距离现在年三月五号快有一年了。除了,最实用的特性是新的数据流。是吧,注是浏览器上的数据流的接口,并解决了上述问题。 使用Intellij IDEA 解决Java8的数据流问题 原文:Fixing Java 8 Stream Gotchas with IntelliJ IDEA 译者:飞龙 协议:CC BY-NC-SA 4.0 ...
摘要:示例字符串数值算术和文件原文译者飞龙协议大量的教程和文章都涉及到中最重要的改变,例如表达式和函数式数据流。不仅仅是字符串,正则表达式模式串也能受益于数据流。 Java 8 API 示例:字符串、数值、算术和文件 原文:Java 8 API by Example: Strings, Numbers, Math and Files 译者:飞龙 协议:CC BY-NC-SA 4.0 ...
摘要:哪吒社区技能树打卡打卡贴函数式接口简介领域优质创作者哪吒公众号作者架构师奋斗者扫描主页左侧二维码,加入群聊,一起学习一起进步欢迎点赞收藏留言前情提要无意间听到领导们的谈话,现在公司的现状是码农太多,但能独立带队的人太少,简而言之,不缺干 ? 哪吒社区Java技能树打卡 【打卡贴 day2...
阅读 2287·2021-11-22 14:56
阅读 1338·2021-09-24 09:47
阅读 858·2019-08-26 18:37
阅读 2787·2019-08-26 12:10
阅读 1477·2019-08-26 11:55
阅读 3100·2019-08-23 18:07
阅读 2253·2019-08-23 14:08
阅读 579·2019-08-23 12:12