函数式接口

函数式接口是1.8中的新特性,他不属于新语法,更像是一种规范

面向对象接口复习

在这里先回顾一下面向对象的接口,创建接口的关键字为interface,这里创建一个日志接口:

public interface LogService {
void info();
}

众所周知,Java中的接口是不能直接创建实例的,因为他的抽象方法没有得到实现:

当我们想要创建接口实例的时候一般都通过实现类来获取实例:

public class LogServiceImpl implements LogService {
@Override
public void info() {
System.out.println("哈哈哈哈");
}
}

这样我们就可以通过实现来创建这个接口的实例:

public class ApplicationMain {
public static void main(String[] args) {
LogService log = new LogServiceImpl();
log.info();
}
}

对接口中的方法进行实现除了实现类之外,还可以通过匿名内部类的方式来创建接口的实例:

public class ApplicationMain {
public static void main(String[] args) {
LogService log = new LogService() {
@Override
public void info() {
System.out.println("嘿嘿嘿");
}
};
}
}

什么是函数式接口

当一个接口只有一个抽象方法 ( 接口默认实现不算 ) 的时候这个接口就是函数式接口,上面的LogService就属于函数式接口,还有学习线程时的Runnable接口也属于函数式接口

函数式接口还有一个注解为@FunctionalInterface,据我了解这个注解可有可无,它主要起到的是检查的作用,当接口中的抽象方法数量大于1的时候就会报错:

内置常用函数式接口

Java中内置了一些常用的函数式接口,这里介绍其中的四种,不用刻意去记,用到就明白了

函数式接口 参数 返回值 说明
Consumer T void 对类型为T的实例进行操作
Supplier T 返回类型为T的实例
Function<T, R> T R 通过对T的操作返回R的实例
Predicate T boolean 通过对T的操作返回boolean值

通过巧妙的运用函数式接口可以实现回调函数的功能

Lambda表达式

Lambda表达式是1.8中的新特性,主要针对函数式接口的匿名内部类实现做了简化

表达式基本语法

找到上面匿名内部类创建LogService的代码:

public class ApplicationMain {
public static void main(String[] args) {
LogService log = new LogService() {
@Override
public void info() {
System.out.println("嘿嘿嘿");
}
};
}
}

因为创建的实例就是接口本身,所以new的部分就可以省略不写,接口中需要实现的抽象方法只有一个,那么也没有必要指定具体实现的方法名称,简写后如下所示:

public class ApplicationMain {
public static void main(String[] args) {
LogService log = ()->{
System.out.println("哈哈哈哈");
};
log.info();
}
}

Lambda表达式前面的括号( )就代表参数列表,箭头->后面的代码块就代表着实现的具体方法体,如果info方法中有参数就可以这样写:

public class ApplicationMain {
public static void main(String[] args) {
LogService log = (msg)->{
System.out.println(msg);
};
log.info("老八秘制小汉堡");
}
}

使用Lambda表达式创建一个线程:

public class ApplicationMain {
public static void main(String[] args) {
// Runnable为函数式接口,所以可以使用Lambda表达式
new Thread(()->{
System.out.println("另一条线程");
}).start();
System.out.println("Main主线程");
}
}

表达式的简写

使用Lambda表达式代替匿名内部类的写法非常简洁,但是在满足特定条件的情况下,它还可以更简洁:

public class ApplicationMain {
public static void main(String[] args) {
/**
* 在参数列表只有一个参数的情况下,()可以省略不写
* 当代码块中只有一句代码时{}可以省略不写
* 当函数有返回值且代码块中只有一句代码时return可以省略不写
*/
LogService log = msg->System.out.println(msg);
log.info("老八秘制小汉堡");
}
}

Lambda表达式相比匿名内部类还有一个特点,当使用匿名内部类时会为匿名内部类生成一个class文件,而使用Lambda表达式时就不会额外生成class文件,这个不做重点

方法引用

方法引用是1.8中的新特性,配合Lambda表达式使用可以让代码更简洁

方法引用初体验

方法引用中需要的特殊符号为双冒号::,具体表现为以下形式:

表现形式 作用
对象::实例方法 通过对象调用实例中的方法
类::实例方法 通过类调用实例中的方法
类::静态方法 通过类调用实例中的静态方法
类::new 创建该类的实例

当Lambda表达式中只有一句函数调用代码,且调用的目标函数的参数列表和Lambda表达式接收的参数列表一致时就可以使用方法引用,如下所示:

public class ApplicationMain {
public static void main(String[] args) {
// 代表的就是上面表格中表现形式的第一行 对象::实例方法
LogService log = System.out::println;
log.info("老八秘制小汉堡");
// forEach同样可以使用方法引用
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.forEach(System.out::println);
}
}

综合练习

针对上面的函数式接口,Lambda表达式以及方法引用做练习,代码会有些多:

/**
* 综合练习
* 函数式接口 + Lambda表达式 + 方法引用
*/
public class ApplicationMain { public static void main(String[] args) {
// 方法引用 对象::实例方法
strToDate("2021-2-20 22:08:45", System.out::println);
// 方法引用 类::new
System.out.println(dateToStr(Date::new));
// 回调函数:取最大值
Integer integer = strListToIntList(Arrays.asList("135", "541", "244"), list -> {
int maxNumber = 0;
for (Integer item : list) {
if (item > maxNumber) {
maxNumber = item;
}
}
return maxNumber;
});
System.out.println("最大值为:" + integer);
// 实现过滤器功能
List<Integer> list = filter(Arrays.asList(800, 200, 1200, 600, 3000, 2400), item -> item > 1000);
System.out.println(list);
} // Consumer:通过时间字符串快速获取Date对象
public static void strToDate(String date, Consumer<Date> consumer) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parse = null;
try {
parse = sdf.parse(date);
} catch (ParseException e) {
System.err.println("转换失败!");
}
consumer.accept(parse);
} // Supplier:通过Date对象快速获取到时间字符串
public static String dateToStr(Supplier<Date> supplier) {
Date date = supplier.get();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date);
} // Function:将String集合转换为Integer,后续操作交给调用者
public static Integer strListToIntList(List<String> list, Function<List<Integer>, Integer> function) {
ArrayList<Integer> integerList = new ArrayList<>();
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String next = iterator.next();
Integer integer = Integer.valueOf(next);
integerList.add(integer);
}
return function.apply(integerList);
} // predicate:返回大于1000的数字
public static List<Integer> filter(List<Integer> list, Predicate<Integer> predicate) {
ArrayList<Integer> target = new ArrayList<>();
for (Integer item : list) {
if (predicate.test(item)) {
target.add(item);
}
}
return target;
} }

JDK8新特性(一) Lambda表达式及相关特性的更多相关文章

  1. jdk8新特性--使用lambda表达式的延迟执行特性优化性能

    使用lambda表达式的延迟加载特性对代码进行优化:

  2. java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合

    java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...

  3. JDK1.8新特性(一) ----Lambda表达式、Stream API、函数式接口、方法引用

    jdk1.8新特性知识点: Lambda表达式 Stream API 函数式接口 方法引用和构造器调用 接口中的默认方法和静态方法 新时间日期API default   Lambda表达式     L ...

  4. Java8 新特性学习 Lambda表达式 和 Stream 用法案例

    Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...

  5. JDK8新特性之Lambda表达式

    Lambda表达式主要是替换了原有匿名内部类的写法,也就是简化了匿名内部类的写法.lambda语法结构: (参数1,参数2...)->{重写方法的内容,不定义方法名} 先看一个使用匿名内部类定义 ...

  6. JDK8新特性02 Lambda表达式02_Lambda语法规则

    //函数式接口:只有一个抽象方法的接口称为函数式接口. 可以使用注解 @FunctionalInterface 修饰 @FunctionalInterface public interface MyF ...

  7. JDK8新特性01 Lambda表达式01_设计的由来

    1.java bean public class Employee { private int id; private String name; private int age; private do ...

  8. JDK8新特性:Lambda表达式

    Lambda表达式,案例一:new Thread(() -> System.out.println("thread")); Lambda表达式,案例二:由参数/箭头和主体组成 ...

  9. Java8新特性之Lambda表达式

    lambda表达式是java8给我们带来的几个重量级新特性之一,借用lambda表达式,可以让我们的java程序设计更加简洁.最近新的项目摒弃了1.6的版本,全面基于java8进行开发,本文是java ...

随机推荐

  1. Oracle kill locked sessions

    select * from v$locked_object; select * from v$session where sid in (select session_id from v$locked ...

  2. 小白养成记——Java比较器Comparable和Comparator

    一.使用情景 1.  调用Arrays.sort()方法或Collections.sort()方法对自定义类的对象排序 以Arrays.sort()为例.假定有如下自定义的Person类 1 publ ...

  3. WPF -- 一种实现本地化的方法

    本文介绍一种WPF程序实现本地化的方法. 步骤 首先,假设xaml文件中存在一个Button按钮,内容为"按钮",实现本地化的步骤如下: 展开程序的Properties,双击Res ...

  4. Qt+opencv亲自配置教程

    了别人的配置,总是无法配置成功,自己慢慢摸索配置成功.我失败的原因是在于自己本机的环境变量和他们不同,特此记下,分享给有相同问题的朋友. 一.需要软件 1.cmake 3.11.3(版本无所谓) 2. ...

  5. Aliyun Oss 上传文件

    目录 Aliyun OSS OSS 简介 OSS 基本概念 OSS 功能概述 OSS 使用 创建存储空间Bucket 创建子目录 Java编码 测试 Aliyun OSS OSS 简介 阿里云对象存储 ...

  6. vscode中js文件使用typescript语法报错,如何解决

    原因:由于vcode自身的语法检查有些问题 解决办法:在设置里面加上 "javascript.validate.enable": false 禁用默认的 js 验证 总结: 由于v ...

  7. C++的标识符的作用域与可见性

    下面是关于C++的标识符的作用域与可见性学习记录,仅供参考 标识符的作用域与可见性 作用域是一个标识符在程序正文中有效的区域. 作用域分类 ①函数原型作用域 ②局部作用域(快作用域) ③类作用域 ④文 ...

  8. sanic-jwt 的使用

    Sanic 是基于 Python 的一个支持高并发的异步 web 框架,sanic-jwt 则是针对Sanic 开发的一个基于 PyJWT 封装的 JWT 授权认证模块. sanic-jwt 项目主页 ...

  9. Maven基础&&Spring框架阶段常用工具类整理

    常用工具类 1.密码加密工具类: package com.itheima.utils; import java.security.MessageDigest; import sun.misc.BASE ...

  10. Stone Game, Why are you always there? HDU - 2999

    题目链接:https://vjudge.net/problem/HDU-2999 题意:有N堆石头,两个人交替取,每次只能取连续的k个石子,最后没有石子取得人输. 思路:如果我们每次取靠边的k个,那么 ...