[Java进阶] 函数式编程以及Lambda表达式

目录

🌰举个例子

🍉Lambda表达式的组成

🍉使用Lambda的前提

🍉Lambda还能省?

🍉常用的函数式接口

🍉Lambda表达式和匿名内部类做参数的区别


写在前面

在之前的面向对象编程中, 代码都是更加倾向于使用对象去操作, 对象做了什么, 对象怎么做,而函数式编程中, 省略了能推导出来的部分的代码, 更倾向于, "做什么"的逻辑.

🌰举个例子

当想创建线程对象, 给定线程任务时, 可以使用匿名内部类去编写:

创建的Runnable接口实现类对象重写的run方法完成的逻辑

Thread t1 = new Thread(new Runnable{
    public void run(){
        System.out.println("这个是使用匿名内部类创建的线程任务");
    }
});
t1.start();

使用函数式编程Lambda表达式实现相同的逻辑

是Thread的参数接口的实现类对象的抽象方法里面的逻辑

Thread t2 = new Thread(()->System.out.println("这个是使用Lambda表达式写的线程任务"));
t2.start();

同样的逻辑, 使用Lambda表达式让我们的代码更少, 看起来更工整

🍉Lambda表达式的组成

() : 里面没有内容, 表示参数为空

->: 表示指向逻辑

{} : 代码块, 方法体中的内容, 编写逻辑 

🍉使用Lambda的前提

调用方法时, 方法的参数是一个接口类型, 接口是函数式接口时, 可以使用Lambda表达式编写抽象方法的实现逻辑作为参数传递

什么是函数式接口(专门为Lambda而生的接口)

这个接口中只能存在一个抽象方法, 但不对其他方法做限制, 为了规范自定义的函数式接口, 可以使用 @FunctionalInterface 去规范限制

🍉Lambda还能省?

Lambda的使用必须具备可推导的环境. 系统能推导出来的内容就可以省略 

标准格式是()->{} , 但是满足一定条件的情况下, Lambda表达式还能再省略

1. 当只有一个参数情况下, 小括号()和参数的数据类型可以不写

public interface Flyable {
// 接口中只有一个字符串类型的s 作为参数
    String fly(String s);
}

class Test{
    public static void main(String[] args) {
//    在调用方法时,可以省略小括号和该参数的数据类型
        fly(s->{
            s = "鸟儿用翅膀飞翔!";
            return s;
        });
    }   
    public static void fly(Flyable flyable){
        System.out.println(flyable);
    }
}

2.当{} 中逻辑只有一句代码时, 可以省略{}, return也可以省略

public interface Flyable {
    String fly(String s);
}

class Test{
    public static void main(String[] args) {
        fly((s)-> s+"用翅膀飞");
    }
    public static void fly(Flyable flyable){
        String s = "鸟儿";
        System.out.println("鸟儿怎么飞:"+flyable.fly(s));
    }
}

3. 参数的类型可以省略(要么都省略, 要么不省略)

public interface Calculate {
    int cal(int a, int b);
}

class Test{
    public static void main(String[] args) {
        count((a,b)-> a+b);
    }
    public static void count(Calculate calculate){
        int result = calculate.cal(10,50);
        System.out.println("计算结果为:"+result);
    }
}

🍉常用的函数式接口

函数式接口只有一个抽象方法, 功能有限, 因此正常的业务很少需要自己编写一个函数式接口, 但是java.util.function中提供了很多可以使用的函数式接口工具

1.消费型: Consumer<T>接口

public class Demo {
    public static void main(String[] args) {
        useConsumer(s -> System.out.println(s));
    }
    public static void useConsumer(Consumer<String> consumer){
        String s = "今天好吗?";
        //消费这个字符串
        //Consumer的accept方法没有返回值, 使用打印 消费数据
        consumer.accept(s);
    }
}

foreach方法的参数是Consumer接口

public class Demo {
    public static void main(String[] args) {
        //使用foreach遍历单列集合
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"张三","李四","王五","赵六");
        list.forEach(s-> System.out.print(s+" "));

        System.out.println("=======无情分割线=======");

        //使用foreach遍历双列集合
        Map<String,Integer> map = new HashMap<>();
        map.put("张三",19);
        map.put("李四",21);
        map.put("王五",13);
        map.forEach((k,v)-> System.out.println(k+":"+v));
    }
}

2.供给型: Supplier<T> 接口

//当需要提供指定类型的数据时,使用
public class Demo {
    public static void main(String[] args) {
        useSupplier(()-> new Random().nextInt(100));
    }

    public static void useSupplier(Supplier<Integer> supplier){
        Integer num = supplier.get();
        System.out.println("本次得到的数据是:"+num);
    }
}

3.谓词型 Predicate<T>接口

//编写自定义的判断逻辑 返回boolean
public class Demo {
    public static void main(String[] args) {
        usePredicate(s->{
            boolean re = s.length()==2;
            return re;
        });
    }
    public static void usePredicate(Predicate<String> predicate){
        String s = "倪妮";
        //test方法返回boolean结果
        boolean result = predicate.test(s);
        System.out.println("字符串"+s+"是否符合自定义Predicate规则:"+result);
    }
}

removeIf方法批量删除单列集合数据,参数是Predicate

public class Demo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"张三","李四","王五","张三","赵六","张三");

        //removeIf只有单列集合可以使用
        //删除索引以张开头的内容
        list.removeIf(s->{
           boolean re = s.startsWith("张");
           return re;
        });
        //使用foreach遍历
        list.forEach(s-> System.out.println(s));
    }
}

4.转换型 Function<T, R>接口

//将参数类型数据 转换成另一种类型并返回
public class Demo {
    public static void main(String[] args) {
        useFunction(s -> Integer.parseInt(s));
    }

    public static void useFunction(Function<String,Integer> function){
        String s = "60";
        Integer i = function.apply(s);
        System.out.println("转换后的结果和3相加得:"+(i+3));
    }
}

🍉Lambda表达式和匿名内部类做参数的区别

1.所需类型:

匿名内部类可以是接口, 也可以是抽象类, 还可以是具体类

Lambda表达式只能是接口

2.使用限制:

如果接口中只有一个抽象方法, 既可以使用匿名内部类也可以使用Lambda表达式

如果接口中多于一个抽象方法, 只能使用匿名内部类

3.编译后的文件

匿名内部类编译后产生单独的.class字节码文件

Lambda表达式编译后, 没有单独的.class字节码文件, 对应的字节码文件会在运行时动态生成

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值