Java~新时代程序员的编码风格:lambda表达式、函数式接口、Stream流式计算、链式编程、异步调用

前言

如果有同学去逛一些新出来的开源项目和框架,你肯定会看到大量的lambda表达式、函数式接口、链式编程、Stream流式计算。

所以现在如果还不熟悉这几个技术,你就会发现看源码非常吃力。

Lambda表达式

基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }

Lambda表达式由三部分组成:

  • paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
  • ->:可理解为“被用于”的意思
  • statements:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。

语法精简

  1. 参数类型可以省略,如果需要省略,每个参数的类型都要省略。
  2. 参数的小括号里面只有一个参数,那么小括号可以省略
  3. 如果方法体当中只有一句代码,那么大括号可以省略
  4. 如果方法体中只有一条语句,其是return语句,那么大括号可以省略,且去掉return关键字。

那么lambda为什么好用呢?
首先一点它主要用在函数式接口上,那下面我再讲讲函数式接口。

Lambda表达式的好坏

Lambda表达式的优点很明显,从核心原理来说他使用的是匿名内部类,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。

  • 优点:
    代码简洁,开发迅速
    方便函数式编程, 只要是函数型接口,都能使用lambda表达式简化
    非常容易进行并行计算
    Java 引入 Lambda,改善了集合操作
  • 缺点:
    代码可读性变差
    在非并行计算中,很多计算未必有传统的 for 性能要高
    不容易进行调试

函数式接口

首先看其定义:

  1. 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
  2. 如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的,保证安全。
@FunctionalInterface 
public interface Runnable { 
    public abstract void run(); 
}

四大函数式接口

在这里插入图片描述

Function函数式接口

Function 函数型接口, 有一个输入参数,有一个输出
在这里插入图片描述

    public static void main(String[] args) {
        //输出大写后的原字符串
        Function<String, String> function = str -> str.toUpperCase();

        System.out.println(function.apply("abc"));
    }
Predicate断定型接口

有一个输入参数,返回值只能是 布尔值!
在这里插入图片描述

    public static void main(String[] args) {
        //判断一个字符串是否为a开头
        Predicate<String> predicate = s -> !s.isEmpty() && s.charAt(0) == 'a';

        System.out.println(predicate.test("abc"));
    }
Consumer 消费型接口

只有输入没有输出
在这里插入图片描述

    public static void main(String[] args) {
        //输出一个大写字符串
        Consumer<String> consumer = s -> System.out.println(s.toUpperCase());

        consumer.accept("abc");
    }
Supplier 供给型接口

没有输出值,只有输出值

在这里插入图片描述

    public static void main(String[] args) {
        //返回一个Demo对象
        Supplier<Demo> supplier = () -> {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);

        List<User> list = 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

而且它的泛型参数是设置的返回值类型。

他有俩种启动方法
在这里插入图片描述
runAsync看参数就是一个runnable参数异步执行肯定时没有返回值的,而上面说到的supplyAsync是一个生产者接口,所以他的作用就是有返回值的。

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //无返回值的异步调用, 俩秒后输出我爱你
        CompletableFuture<Void> future = 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";
        CompletableFuture<Integer> completableFuture = 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());

    }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值