IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Java8如何使用Lambda表达式简化匿名内部类 -> 正文阅读

[网络协议]Java8如何使用Lambda表达式简化匿名内部类

函数式接口(FunctionalInterface)

函数式接口简介

只包含一个抽象方法的接口,称为函数式接口。

我们可以通过Lambda表达式来创建该接口的对象。如果Lambda表达式抛出一个非运行时异常,那么该异常需要在目标接口的抽象方法上进行声明。

Java8中用@FunctionalInterface来检查函数式接口,当然我们也可以在自己写的接口上使用这个注解来检查接口是否是函数式接口。
在这里插入图片描述
在java.util.function包下定义了许多函数式接口。


Java内置的四大核心函数式接口

函数式接口参数类型返回值类型作用
Consumer消费型接口Tvoid对传入的类型为T的对象进行处理
Supplier供给型接口T返回类型为T的对象
Function<T,R> 函数型接口TR对T类型的对象进行处理并且返回类型为R的对象
Predicate 断定型接口Tboolean判断类型为T的对象是否满足某种约束
@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);
    
}
@FunctionalInterface
public interface Supplier<T> {

    T get();
    
}
@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

}
@FunctionalInterface
public interface Predicate<T> {
    
    boolean test(T t);
    
}

其他部分接口

函数式接口参数类型返回值类型作用
BiFunction<T,U,R>T, UR对类型为T,U的参数进行操作,返回R类型的结果。
UnaryOperator(Function子接口)TT对类型为T的对象进行一元运算,并返回T类型的结果。
BinaryOperator(BiFunction子接口)T, TT对类型为T的对象进行二元运算,并返回T类型的结果。
BiConsumer<T,U>T,Uvoid对类型为T,U参数进行操作。
BiPredicate<T,U>T,Uboolean判断参数T,U是否满足某种约束
ToIntFunction,ToLongFunction,ToDoubleFunctionTint,long,double分别计算int、long、double值的函数
IntFunction,LongFunction,DoubleFunctionint,long,doubleR参数分别为int、long、double类型的函数

看着貌似多了很多接口,其实并没有脱离接口原来的作用,只是jdk提供一个接口带着一个抽象方法供开发者自己去实现。函数式接口的定义也是为了提供一种新的语法:Lambda表达式。如果有需要,完全可以自己定义函数式接口。



Lambda表达式

Lambda表达式是啥?

众所周知,Java提倡的是”一切皆对象“。但是一些新的语言及技术的兴起,Java不得不做出调整以支持更加广泛的技术要求,也就是需要支持OOF(面向函数编程)。

在函数式编程语言中,Lambda表达式的类型是函数。但是在Java中,Lambda表达式的类型是对象,且必须依附于函数式接口。简单来说,Lambda表达式就是函数式接口的实例,只要一个对象是函数式接口的实例就可以用Lambda表达式来表示。所以,以前用匿名实现类表示的都可以用Lambda表达式来编写。

Lambda表达式是Java8引入的一种新的语法。这里又用到一种新的操作符,这个操作符就是”->”,称为Lambda表达式操作符或者箭头操作符。

该操作符将Lambda表达式分为两个部分:

左侧:指定了Lambda表达式需要的参数列表。

右侧:指定了Lambda表达式体,是抽象方法的实现逻辑,也即Lambda 表达式要执行的功能。

Lambda表达式基本的语法格式:

(参数列表) -> {Lambda表达式体}

为什么要用Lambda表达式?

Lambda表达式是一个匿名函数,是一段可以传递的代码。使用Lambda表达式能够写出更简洁、更灵活的代码。

既然Lambda表达式是一个函数式接口的实例,那么就找一个函数式接口来应用一下。
在这里插入图片描述
在之前用匿名内部类创建一个Runnable接口对象是这样写的:

Runnable run = new Runnable() {
    @Override
    public void run() {
    	System.out.println("###");
    }
};

现在可以这样写:

Runnable run = () -> {System.out.println("lambda表达式实现");};

一行代码就实现了之前好多行代码的功能,确实很简洁。

Lambda表达式的使用语法

  1. 无参数,无返回值
Runnable run = () -> {System.out.println("lambda表达式实现");};

如果执行语句只有一行,可以省略”{}“:

Runnable run = () -> System.out.println("lambda表达式实现");
  1. 有一个参数,无返回值
Consumer<String> consumer = (String s) -> {System.out.println(s);};

参数类型可以省略,因为编译器会根据上下文环境推断出参数的类型,也叫做类型推断。这里指定了泛型为String。

而且只有一个参数时,参数列表的”()“也可以省略。所以可以这么写:

Consumer<String> consumer =  s -> System.out.println(s);
  1. 有多个参数,有返回值
Comparator<Integer> comparator1 = (o1,o2) -> {
    System.out.println(o2);
    return Integer.compare(o1,o2);
};
  1. 只有一条执行语句且有返回值
Comparator<Integer> comparator1 = (o1,o2) -> {
    return Integer.compare(o1,o2);
};

如果有返回值时只有一条执行语句,那么”return“可以省略。

Comparator<Integer> comparator1 = (o1,o2) -> Integer.compare(o1,o2);
  1. 将Lambda表达式作为参数传递
Thread thread = new Thread(() -> {
    System.out.println("lambda表达式实现");
});

为了将Lambda 表达式作为参数传递,接收Lambda 表达式的参数类型必须是与该Lambda 表达式兼容的函数式接口的类型。比如上面代码中的Lambda表达式的作用就是创建了一个Runnale对象,而new Thread()的参数可以是一个Runnable对象。



方法引用和构造器引用

方法引用

方法引用是Lambda表达式的另一种表现形式。简单来说,就是将Lambda表达式的内容封装成一个方法再进行调用或者已经有现成的方法可以直接使用。

方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。

要求:实现接口的抽象方法的参数列表和返回值类型必须与方法引用的方法的参数列表和返回值类型保持一致!

方法引用中引入了一个新的操作符:“::”

使用格式:类(或对象):: 方法名

具体分为三种情况:

  1. 对象::非静态方法名
  2. 类::静态方法名
  3. 类::非静态方法名

举个简单的例子:

比如遍历一个集合,将每个对象打印出来,原来是这样写:

@Test
public void test() {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    for (Integer integer : list) {
        System.out.println(integer);
    }
}

Java8提供一个新方法forEach进行遍历:

而该方法的参数是一个消费型接口,有一个入参,而返回值为void。

而System.out.println方法的入参格式和返回值格式正好与之相同。也就是满足方法引用的要求。现在可以改造成这样:

 @Test
 public void test01() {
     List<Integer> list = new ArrayList<>();
     list.add(1);
     list.add(2);
     list.add(3);
     // list.forEach(integer -> System.out.println(integer));
     list.forEach(System.out::println);
 }

又或者这种情况:

BiPredicate<String, String> biPredicate = (s1,s2) -> s1.equals(s2);
// 等同于
BiPredicate<String, String> biPredicate1 = String::equals;

注意:当函数式接口方法的第一个参数是引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数)时:ClassName::methodName

构造器引用

构造器引用无非就是方法引用的一种特殊类型。虽然构造器理论上没有返回值,但是变相地又有返回值(对象)。

// 创建一个对象
String s = new String();

那不是和供给型接口类似吗,这个时候就可以使用构造器引用。

格式:ClassName::new

要求:构造器参数列表要与接口中抽象方法的参数列表一致!且方法的返回值即为构造器对应类的对象。

例如:

Supplier<String> stringSupplier = () -> new String();
// 等价于
Supplier<String> stringSupplier = String::new;

数组也可以:

Function<Integer, Integer[]> function = (i) -> new Integer[i];
// 等价于
Function<Integer, Integer[]> function = Integer[]::new;
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 13:06:47  更:2022-05-09 13:07:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 10:56:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计