
Java~新时代程序员的编码风格:lambda表达式、函数式接口、Stream流式计算、链式编程、异步调用
runAsync看参数就是一个runnable参数异步执行肯定时没有返回值的,而上面说到的supplyAsync是一个生产者接口,所以他的作用就是有返回值的。
发布日期:2021-05-07 13:59:16
浏览次数:22
分类:技术文章
本文共 5913 字,大约阅读时间需要 19 分钟。
文章目录
前言
如果有同学去逛一些新出来的开源项目和框架,你肯定会看到大量的lambda表达式、函数式接口、链式编程、Stream流式计算。
所以现在如果还不熟悉这几个技术,你就会发现看源码非常吃力。
Lambda表达式
基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }
Lambda表达式由三部分组成:
- paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
- ->:可理解为“被用于”的意思
- statements:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。
语法精简
- 参数类型可以省略,如果需要省略,每个参数的类型都要省略。
- 参数的小括号里面只有一个参数,那么小括号可以省略
- 如果方法体当中只有一句代码,那么大括号可以省略
- 如果方法体中只有一条语句,其是return语句,那么大括号可以省略,且去掉return关键字。
那么lambda为什么好用呢?
首先一点它主要用在函数式接口上,那下面我再讲讲函数式接口。Lambda表达式的好坏
Lambda表达式的优点很明显,从核心原理来说他使用的是匿名内部类,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。
- 优点: 代码简洁,开发迅速 方便函数式编程, 只要是函数型接口,都能使用lambda表达式简化 非常容易进行并行计算 Java 引入 Lambda,改善了集合操作
- 缺点: 代码可读性变差 在非并行计算中,很多计算未必有传统的 for 性能要高 不容易进行调试
函数式接口
首先看其定义:
- 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
- 如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的,保证安全。
@FunctionalInterface public interface Runnable { public abstract void run(); }
四大函数式接口
Function函数式接口
Function 函数型接口, 有一个输入参数,有一个输出

public static void main(String[] args) { //输出大写后的原字符串 Functionfunction = str -> str.toUpperCase(); System.out.println(function.apply("abc")); }
Predicate断定型接口
有一个输入参数,返回值只能是 布尔值!

public static void main(String[] args) { //判断一个字符串是否为a开头 Predicatepredicate = s -> !s.isEmpty() && s.charAt(0) == 'a'; System.out.println(predicate.test("abc")); }
Consumer 消费型接口
只有输入没有输出

public static void main(String[] args) { //输出一个大写字符串 Consumerconsumer = s -> System.out.println(s.toUpperCase()); consumer.accept("abc"); }
Supplier 供给型接口
没有输出值,只有输出值
public static void main(String[] args) { //返回一个Demo对象 Suppliersupplier = () -> { return new Demo();}; System.out.println(supplier.get().hashCode()); }
Stream流式计算
这个我之前有文章就不过多讲了,基础流式计算基础东西可以看我之前的博客
今天我要加一点东西就是并行流,让大家体验一下他的好处。我们现在常说的大数据,其实大数据不外乎存储技术和计算技术,其中计算技术大多都是用流来计算。
比如我们现在计算0~10_0000_0000L的和,我写代码大家体验一下他的快速
public static void main(String[] args) { //普通for循环 long sum1 = 0L; long start1 = System.currentTimeMillis(); for (long i = 0L; i < 10_0000_0000L; i++) { sum1 += i; } System.out.println("普通for循环耗时:" + (System.currentTimeMillis() - start1)); long start2 = System.currentTimeMillis(); long sum2 = LongStream.range(0, 10_0000_0000L).parallel().sum(); System.out.println("使用并行流耗时:" + (System.currentTimeMillis() - start2)); }
普通for循环耗时:520使用并行流耗时:290
几乎可以快出一倍。
链式编程
题目要求:一分钟内完成此题,只能用一行代码实现!
- 现在有5个用户!筛选: 1、ID 必须是偶数 2、年龄必须大于23岁 3、用户名转为大写字母 4、用户名字母倒着排序 5、只输出一个用户!
用户的数据结构
static class User { int id; String name; int age; public User(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
实现代码:
public static void main(String[] args) { User u1 = new User(1,"a",21); User u2 = new User(2,"b",22); User u3 = new User(3,"c",23); User u4 = new User(4,"d",24); User u5 = new User(6,"e",25); Listlist = Arrays.asList(u1, u2, u3, u4, u5); list.stream().filter(user -> user.id % 2 == 0) //过滤 .filter(user -> user.age > 23) //过滤 .peek((user) -> user.name = user.name.toUpperCase()) //简单数据 .sorted((uu1, uu2) -> uu2.name.compareTo(uu1.name)) //排序 .limit(1) //限制数量 .forEach(System.out::println); //输出 }
而并行流的核心原理是ForkJoinPool,这个我之前也写过文章,可以参考参考。
Future异步调用
Future 设计的初衷: 对将来的某个事件的结果进行建模,也就是他会异步的执行然后帮助我们保存结果,我们想要结果的时候直接get就行,如果结果还没有出来,get的时候就会阻塞。
最常用的就是他下面的一个实现类: CompletableFuture
而且它的泛型参数是设置的返回值类型。
他有俩种启动方法

public static void main(String[] args) throws ExecutionException, InterruptedException { //无返回值的异步调用, 俩秒后输出我爱你 CompletableFuturefuture = CompletableFuture.runAsync(() -> { System.out.println("进入: " + Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(2); System.out.println("我爱你"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("离开: " + Thread.currentThread().getName()); }); System.out.println("swy:"); //获取其执行结果,如果异步任务没有执行完,此时主线程就会阻塞 future.get(); }
再来看一个异步执行等待返回值的例子
public static void main(String[] args) throws ExecutionException, InterruptedException { //比如我们实现一个web响应状态码,正常返回200,出错返回500 String url = "http://www.baidu.com"; CompletableFuturecompletableFuture = CompletableFuture.supplyAsync(() -> { System.out.println(Thread.currentThread().getName()+"supplyAsync=>Integer"); // URL验证规则 String regEx ="[a-zA-z]+://[^\\s]*"; // 编译正则表达式 Pattern pattern = Pattern.compile(regEx); // 忽略大小写的写法 Matcher matcher = pattern.matcher(url); // 字符串是否与正则表达式相匹配 if (!matcher.matches()) { throw new IllegalStateException(); } return 200; }).whenComplete((t, u) -> { //查看执行完的返回结果或者错误信息 System.out.println("t=>" + t); // 正常的返回结果 System.out.println("u=>" + u); // 错误信息: }).exceptionally((e) ->{ //如果出现异常 System.out.println(e.getMessage()); return 500; }); System.out.println(completableFuture.get()); }
发表评论
最新留言
做的很好,不错不错
[***.243.131.199]2025年04月02日 07时21分47秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
vue自定义封装Loading组件
2019-03-05
解决移动端项目中苹果ios和安卓android手机点击输入框网页页面自动放大缩小
2019-03-05
Element UI 中动态路由的分析及实现
2019-03-05
使用springMVC配置视图管理器后找不到指定的页面
2019-03-05
关于js中对于Promise的深入理解
2019-03-05
对于js中的this指向的深入理解
2019-03-05
杭电 2007 平方和与立方和(输入数据的大小顺序并不能默认)
2019-03-05
十大排序算法之三:插入排序(Python)
2019-03-05
利用Python实现循环队列
2019-03-05
十大排序算法之四:希尔排序(Python)
2019-03-05
利用递归实现二叉树的前中后序遍历(Python)
2019-03-05
A*寻路算法(Python)
2019-03-05
Python刷题输入输出
2019-03-05
C++数组知识注意点
2019-03-05
冒泡排序又来啦(C/C++版本)
2019-03-05
python负数存储
2019-03-05
求二维数组中最大值的位置
2019-03-05
python中sort和sorted的区别
2019-03-05
防碰撞算法
2019-03-05
在vue中添加echarts
2019-03-05