Lambda表达式

概述

Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

使用 Lambda 表达式可以使代码变的更加简洁紧凑。

冗余的Runnable代码

我们在上一篇文章中讲到多线程时,常常用到Runnable接口定义线程的任务

public class demo03InnerThread {
    public static void main(String[] args) {
        Runnable r = new Runnable(){
            @Override
            public void run() {
               System.out.println(Thread.currentThread().getName());
            }
        };
        new Thread(r).start();
    }
}

在匿名内部类中,其实只有方法体才是关键所在,那我们可以不创建这个匿名内部类吗?

Lambda初体验
public class demo01简化Runnable {
    public static void main(String[] args) {
        new Thread(() -> System.out.println(Thread.currentThread().getName())).start();
    }
}

这样我们就将代码简化了

  • ()表示run()方法的参数,此处没有参数‘
  • ->表示将前面的参数传递给后面的代码
  • 后面的输出语句即为业务逻辑代码
Lambda表达式的标准格式

Lambda表达式省去了面向对象的一些条条框框,格式由3部分组成:

  • 一些参数
  • 一个箭头
  • 一段代码
    (参数类型 参数名称) -> {代码}
    没有参数括号中就没有内容,多个参数用逗号隔开

再来举个例子,在排序的时候我们经常用Arrays.sort()方法传入一个比较器自定义比较规则,我么们也可以用Lambda表达式简写

import java.util.Arrays;
import java.util.Comparator;

public class demo02简化Comparator {
    public static void main(String[] args) {
        Integer[] arr = {98, -4, 2, 7, 11, 4, 8};
        //降序排序
        Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        
        //Lambda表达式
        //Arrays.sort(arr, (Integer o1, Integer o2) -> o2 - o1);
        Arrays.sort(arr, (o1, o2) -> o2 - o1);//参数类型可以不写
    }
}

可以省略的内容:

  • 参数列表的数据类型可以省略不写
  • 如果参数只有一个,括号也可以不写
  • 代码只有一行,{}, return 和分号 可以不写(要不写则都不写)
Lambda使用前提
  • 必须具有接口,且接口中仅有一个抽象方法

  • 必须具有上下文推断(参数类型需和接口对应)

      备注:只有一个抽象方法的接口成为函数式接口
    

函数式接口

概述

函数式接口在Java中指的是有且仅有一个抽象方法的接口

函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda。

备注:
“语法糖”是指使用更方便,但原理不变的代码语法。
例如遍历集合时使用的for-each循环,其实底层的实现原理仍然是迭代器,这便是“语法糖”
从应用层面上来讲,Java中的Lambda可以被当作是匿名内部类的“语法糖”,但是二者在原理上不同

注:我们可以用@FunctionInterface注解检测接口是否是一个函数式接口

函数式编程

有些场景的代码在执行后,结果不一定被使用,从而造成浪费。而Lambda表达式是延迟执行的,正好可以作为解决方案,提升性能。

** 性能浪费的日志案例**

package Lambda;
/*
发现以下代码存在性能浪费的问题:
    调用ShowLog方法,传递的第二个参数是一个拼接后的字符串
    先把字符串拼接好,再调用方法
    如果传递的leval等级不为1,则不会输出这个字符串,那么拼接的这个字符串就浪费了
 */
public class demo03性能浪费的日志案例 {
    //根据日志的级别显示日志信息
    public static void showLog(int level, String message){
        if(level == 1)
            System.out.println(message);
    }

    public static void main(String[] args) {
        String message1 = "hello";
        String message2 = "hi";
        String message3 = "happy";
        String message1 = "hello";
        String message2 = "hi";
        String message3 = "happy";
        showLog(2, message1 + message2 + message3);
    }
}

日志案例的优化

package Lambda;
/*
使用Lambda优化日志案例
Lambda的特点:延迟加载
Lambda使用的前提:存在函数式接口

这里使用Lambda表达式,作为参数传递给showLog方法,
仅当level为1时才会调用接口中的方法,才会进行字符串的拼接
如果level不为1,不会进行字符串的拼接9=
 */
public class demo04日志案例的优化 {
    @FunctionalInterface
    public interface  MessageBuilder{
        //定义一个拼接消息的抽象方法
        public abstract  String builder();
    }

    public static void showLog(int level, MessageBuilder mb){
        if(level == 1)
            System.out.println(mb.builder());
    }

    public static void main(String[] args) {
        String message1 = "hello ";
        String message2 = "hi ";
        String message3 = "happy";
        showLog(1, () -> message1 + message2 + message3);
    }
}

常用的函数式接口

Supplier接口

java.util.function.Supplier<T>接口仅包含一个无参的方法<T> get()。用来获取一个泛型参数指定类型的对象数据。

package Lambda;

import java.util.function.Supplier;

/*
Supplier接口被称为生产型接口,指定接口的泛型是什么类型,接口的中的get方法就会生产什么类型的数据
 */
public class demo05Supplier {
    public static String getString(Supplier<String> sup){
        return sup.get();
    }

    public static void main(String[] args) {
        System.out.println(getString(() -> "我是彭于晏"));
    }
}

package Lambda;

import java.util.function.Supplier;

/*
Supplier接口被称为生产型接口,指定接口的泛型是什么类型,接口的中的get方法就会生产什么类型的数据
 */
public class demo06Supplier求数组最大元素 {
    public static Integer getMax(Supplier<Integer> sup){

        return sup.get();
    }

    public static void main(String[] args) {
        int[] nums = {3,5,2,7,1,9,8,23};
        System.out.println(getMax(() -> {
            int max = nums[0];
            for (int num : nums)
                max = Math.max(max, num);
            return max;
        }));
    }
}

Consumer接口
java.util.function.Consumerr<T>接口与Supplier接口正好相反,他不是生产一个数据,而是消费一个数据,数据类型由泛型决定。

package Lambda;

import java.util.function.Consumer;

public class demo07Consumer {
    public static void solution(String name, Consumer<String> con){
        con.accept(name);
    }

    public static void main(String[] args) {
        //消费数据的方式由自己定义
        solution("彭于晏", (name) -> System.out.println("我是" + name));
        solution("彭于晏", (name) -> System.out.println(new StringBuilder(name).reverse().toString()));
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值