Java8函数式接口及Lambda表达式(闭包)

今天给大家分享一下关于Java8新特性Lambda表达式的相关知识,今天浏览了许多帖子,发现没有很详细的介绍,今天就给大家详细地介绍一下Lambda表达式。

什么是函数式接口?

  1. 函数式接口有且仅有一个抽象方法,但是可以有多个非抽象方法。
  2. 函数式接口可以被隐式转换为Lambda表达式。Lambda就是Java中函数式编程的体现。
  3. 主要分布在java.util.function包下,常见的4大原始函数接口为:Function(函数型接口)、Predicate(断定型接口)、Consumer(消费型接口)、Supplier(供给型接口)。

3542280a0fd1477191495ffdbe022e6f.pngFunction接口

4.常见的函数式接口

d3dafd3088034745a338f87770048c71.png

@FunctionalInterface注解

  1. Java 8中专门为函数式接口引入了一个新的注解: @FunctionalInterface。该注解放在接口上,表示此接口是一个函数式接口。 并且提示编译器去检查接口是否仅包含一个抽象方法,即,是否符合函数式编程的定义
  2. 注意:如果自定义一个符合规范的函数式接口,也可以不加@Functionalinterface注解,此注解只是起到一个提示编译器进行规范检查的作用;
  3. 日常开发中用的最多的函数式接口的,比如线程中的 Runnable.还有Callable

01e300e2fbc54bda8696cf10527f6e14.png

常见函数式接口的使用

  • Function(函数型接口):

输入输出的参数:有一个输入的参数,有一个输出的参数;必须实现R apply(T t)方法,代码示例
import org.junit.jupiter.api.Test;

import java.util.function.Function;

public class FunctionTest {
    @Test
    public void tradition() {
        // 初始化,并且实现接口唯一实现方法
        Function<String, String> function = new Function<>() {
            @Override
            public String apply(String param) {
                return param;
            }
        };
        System.out.println(function.apply("Hello, Function!"));
    }

    @Test
    public void lambda() {
        // 使用Lambda表达式实现
        Function<String, String> function = (param) -> {
            return param;
        };
        // Function<String, String> function = param -> param;
        System.out.println(function.apply("Hello, Function!"));
    }
}
  • Predicate(断定型接口):

输入输出的参数:有一个输入的参数,返回值只能是boolean;必须实现boolean test(T t)方法,代码示例

import org.junit.jupiter.api.Test;

import java.util.function.Predicate;


public class PredicateTest {
    @Test
    public void tradition() {
        // Predicate 谓语,断言
        Predicate<Integer> predicate = new Predicate<>() {
            @Override
            public boolean test(Integer integer) {
                /*if (integer > 0) {
                    return true;
                }
                return false;*/
                return integer > 0;
            }
        };
        System.out.println(predicate.test(5));
    }

    @Test
    public void lambda() {
        Predicate<Integer> predicate = integer -> integer > 0;
        System.out.println(predicate.test(5));
    }
}
  • Consumer(消费型接口):

只有输入参数,没有返回值;必须实现void accept(T t);代码示例

import org.junit.jupiter.api.Test;

import java.util.function.Consumer;


public class ConsumerTest {
    @Test
    public void lambda() {
        Consumer<String> consumer = str -> System.out.println(str);
        consumer.accept("Hello, Consumer!");
    }
}
  • Supplier(供给型接口):

没有参数,只有返回值;必须实现T get();方法;代码示例
import org.junit.jupiter.api.Test;

import java.util.function.Supplier;

public class SupplierTest {
    @Test
    public void lambda() {
        Supplier<Integer> supplier = () -> 1024;
        System.out.println(supplier.get());
    }
}

 

函数式接口使用Lambda表达式语法总结

Lambda 表达式

  1. Lambda表达式(闭包):java8的新特性,lambda运行将函数作为一个方法的参数,也就是函数作为参数传递到方法中。使用lambda表达式可以让代码更加简洁;
  2. lambda表达式,其实本质来讲,就是一个匿名函数。因此在写lambda表达式的时候,不需要关心方法名是什么。实际上,我们在写lambda表达式的时候,也不需要关心返回值类型;
  3. 接口实现,可以有很多种方式来实现。例如:设计接口的实现类、使用匿名内部类。但是lambda表达式,比这两种方式都简单.lambda表达式,只能实现函数式接口。

声明:函数式接口名 对象名 = (抽象方法的形参名) -> { // 方法体 };

使用:对象名.抽象方法(实参)

注意事项:

  1. Lambda表达式仍然是隐式实现了该接口,和匿名内部类非常相似d3f101eab0a04c1fb5f66982b4579b54.png
  2. Lambda表达式仍然是一条语句,末尾必须带上;这点也和匿名内部类相似
  3. ()中如果只有一个参数,小括号可以省略,其他情况(没有参数、有多个参数)不可以省略
  4. ()中参数的类型可以省略,直接写参数名
  5. {}中如果只有一条语句,大括号可以省略,其他情况不可以省略(如果只有一条return语句,return关键字可以省略)

Lambda 函数引用

介绍:Lambda表达式是为了简化接口的实现的。在lambda表达式中,不应该出现比较复杂的逻辑。 如果在lambda表达式中需要处理逻辑复杂,可以单独写一个方法。在lambda表达式中直接引用这个方法即可。

函数引用: 引用一个已经存在的方法,使其替代lambda表达式完成接口的实现。代码实例:

首先编写一个计算器类,其中有一个静态方法,一个非静态方法:

public class Calculator {
    public static int calculate(int a, int b){
        if (a > b){
            return a - b;
        }
        return b - a;
    }
    public int getMax(int a, int b) {
        return Math.max(a, b);
    }
}

 

静态引用

引用其他类(一般是工具类)的静态方法

使用:在引用的方法后面,不要添加小括号;引用的这个方法,参数(数量、类型)和返回值,必须要跟接口中定义的一致(方法名可以不一致,被引用的类Calculator不需要实现该接口),代码:

public class StaticRefer {
    public static void main(String[] args) {
        // 实现多个参数一个返回值的接口
        // 对一个静态方法的引用,语法:类名::静态方法名
        TestStatic test = Calculator::calculate;// 这句话完成了对TestStatic接口的匿名实现
        System.out.println(test.calc(4, 5));
        System.out.println(test.getClass());

    }
}

@FunctionalInterface
interface TestStatic {
    int calc(int a, int b);
}

 

非静态引用

引用其他类(一般是工具类)的普通成员方法

public class NoStaticRefer {
    public static void main(String[] args) {
        // 实现多个参数一个返回值的接口
        // 对非静态方法的引用,语法:对象::方法名
        TestNoStatic test = new Calculator()::getMax;
        System.out.println(test.calc(9, 5));
    }
}

interface TestNoStatic {
    int calc(int a, int b);
}

 

构造方法的引用

如果某一个函数式接口中定义的方法,仅仅是为了得到一个类的对象。此时我们就可以使用构造方法的引用,简化这个方法的实现。

语法:类名::new

代码实现:

public class StructureRefer {
    public static void main(String[] args) {
        GetPerson getPerson = Person::new;// 这句话完成了对GetPerson接口的匿名实现
        System.out.println(getPerson.getClass());
        Person lucy = getPerson.getPerson("Lucy", 30);
        System.out.println(lucy);
    }
}
// Person类
class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
// 定义一个函数式接口用于获取对象
@FunctionalInterface
interface GetPerson {
    Person getPerson(String name, int age);
}

 

Lambda表达式与匿名内部类对比

  1. 匿名内部类: 可以是接口,也可以是抽象类,还可以是具体类;
  2. Lambda表达式,只可能是接口,如果接口中仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名表达式
  3. 如果接口中有多个抽象,只能使用匿名内部类

总结

  1. 函数式接口应用在函数式编程中,Lambda表达式是函数式编程的提现
  2. 通过函数式接口和Lambda表达式可以简化代码,提高开发效率。
  3. 同时可能会不利于代码调试,或者对于不熟悉函数式编程的同事不容易阅读对应代码。

欢迎各位大佬在留言区讨论和指正,有需要其他讲解的请在评论区留言!


文章中部分资源及名词来源于互联网,如有侵权,请联系删除。

文章为原创内容,转载请标明原作者@Pacey王

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值