今天给大家分享一下关于Java8新特性Lambda表达式的相关知识,今天浏览了许多帖子,发现没有很详细的介绍,今天就给大家详细地介绍一下Lambda表达式。
什么是函数式接口?
- 函数式接口有且仅有一个抽象方法,但是可以有多个非抽象方法。
- 函数式接口可以被隐式转换为Lambda表达式。Lambda就是Java中函数式编程的体现。
- 主要分布在java.util.function包下,常见的4大原始函数接口为:Function(函数型接口)、Predicate(断定型接口)、Consumer(消费型接口)、Supplier(供给型接口)。
Function接口
4.常见的函数式接口
@FunctionalInterface注解
- Java 8中专门为函数式接口引入了一个新的注解: @FunctionalInterface。该注解放在接口上,表示此接口是一个函数式接口。 并且提示编译器去检查接口是否仅包含一个抽象方法,即,是否符合函数式编程的定义
- 注意:如果自定义一个符合规范的函数式接口,也可以不加@Functionalinterface注解,此注解只是起到一个提示编译器进行规范检查的作用;
- 日常开发中用的最多的函数式接口的,比如线程中的 Runnable.还有Callable
常见函数式接口的使用
-
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 表达式
- Lambda表达式(闭包):java8的新特性,lambda运行将函数作为一个方法的参数,也就是函数作为参数传递到方法中。使用lambda表达式可以让代码更加简洁;
- lambda表达式,其实本质来讲,就是一个匿名函数。因此在写lambda表达式的时候,不需要关心方法名是什么。实际上,我们在写lambda表达式的时候,也不需要关心返回值类型;
- 接口实现,可以有很多种方式来实现。例如:设计接口的实现类、使用匿名内部类。但是lambda表达式,比这两种方式都简单.lambda表达式,只能实现函数式接口。
声明:函数式接口名 对象名 = (抽象方法的形参名) -> { // 方法体 };
使用:对象名.抽象方法(实参)
注意事项:
- Lambda表达式仍然是隐式实现了该接口,和匿名内部类非常相似
- Lambda表达式仍然是一条语句,末尾必须带上;这点也和匿名内部类相似
- ()中如果只有一个参数,小括号可以省略,其他情况(没有参数、有多个参数)不可以省略
- ()中参数的类型可以省略,直接写参数名
- {}中如果只有一条语句,大括号可以省略,其他情况不可以省略(如果只有一条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表达式与匿名内部类对比
- 匿名内部类: 可以是接口,也可以是抽象类,还可以是具体类;
- Lambda表达式,只可能是接口,如果接口中仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名表达式
- 如果接口中有多个抽象,只能使用匿名内部类
总结
- 函数式接口应用在函数式编程中,Lambda表达式是函数式编程的提现
- 通过函数式接口和Lambda表达式可以简化代码,提高开发效率。
- 同时可能会不利于代码调试,或者对于不熟悉函数式编程的同事不容易阅读对应代码。
欢迎各位大佬在留言区讨论和指正,有需要其他讲解的请在评论区留言!
文章中部分资源及名词来源于互联网,如有侵权,请联系删除。
文章为原创内容,转载请标明原作者@Pacey王