函数式接口

函数式接口是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. Bitter.NotifyOpenPaltform : HTTP 异步消息接收调度中心&mdash;开源贡献 之 一:简介

    现在互联网的系统越来越趋向于复杂,从单体系统到现在的微服务体系演变.公司与公司的分工也越来越明确. 大数据公司提供了大数据服务 人脸识别公司提供了人脸识别服务 OCR 公司提供了专业的OCR 服务 车 ...

  2. Prism -- 简介

    Prism是一个开源框架,用于在WPF.Xamarin Forms.Uno/Win UI等应用中创建松耦合.可维护.可测试的XAML应用程序.Prism提供了一组设计模式的实现,这些设计模式有助于编写 ...

  3. 利用Visual Studio调试JavaScript脚本

    方法1: 方法2: 打开IE,按F12调试. 方法3: JS断电点debugger代替

  4. 500GJava/Hadoop/Spark/机器学习...视频教程免费分享 百度云持续更新

    参加工作这么长时间了,工作中遇到了不少技能都是看视频教程学习的,相比较看书而言看视频确实比较容易理解.分享一下自己看过的和收集的视频教程. 资源包括: 大数据方面的Hadoop(云帆,小象学院,八斗学 ...

  5. 【白话科普】CDN & 游戏加速器,两者是一个原理吗?

    说起加速,大家可能就会联想到"游戏加速"之类的场景,而说到现在流行的云服务加速,则离不开 CDN 这个词.那么 CDN 和游戏加速器是同一种东西么?从效果上看两者都是为了" ...

  6. java校招笔试题

    基础: Java 反射?反射有什么缺点?你是怎么理解反射的(为什么框架需要反射)? 谈谈对 Java 注解的理解,解决了什么问题? 内部类了解吗?匿名内部类了解吗? BIO和NIO区别,4核cpu,1 ...

  7. SpringBoot启动流程分析原理(一)

    我们都知道SpringBoot自问世以来,一直有一个响亮的口号"约定优于配置",其实一种按约定编程的软件设计范式,目的在于减少软件开发人员在工作中的各种繁琐的配置,我们都知道传统的 ...

  8. C# 应用 - 使用 HttpClient 发起 Http 请求

    1. 需要的库类 \Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Net.Http.dll System.N ...

  9. Apache配置 9.访问控制-Diretory\FileMatch

    (1)介绍 访问控制限制白名单IP,针对文件和目录. (2)目录配置 #vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf <Virtua ...

  10. java 递归求二叉树深度

    给定二叉树,找到它的最大深度. 最大深度是从根节点到最远叶节点的最长路径上的节点数. 注意:叶子是没有子节点的节点. Example: Given binary tree [3,9,20,null,n ...