Lambda表达式、函数式接口
1 Lambda
1.1 概述
Lambda表达式是一种没有名字的函数,也可称为闭包,是Java 8 发布的最重要新特性。
本质上是一段匿名内部类,也可以是一段可以传递的代码。
还有叫箭头函数的...
1.2 为什么要使用Lambda表达式
Lambda表达式就是一个匿名内部类的简写方式
使程序更加简洁清晰,编程效率也得到了提高
1.3 和匿名内部类对比
更加简介清晰
1.4 语法结构
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
如果不写{} return 不能写 分号不能写
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值
如果只有一条语句,并且是返回值语句,就可以不写return 不写 {}
如果写上{} 就必须写return 和 ;
如果有 多条语句,必须写{} return 和 ; 也必须写
1.5 案例
1 不需要参数,返回值为5
()-> 5
2 接收一个参数(数字类型),返回其2倍的值
x -> x*2
3 接受2个参数(数字),并返回他们的差值
(x,y)-> x-y
1.6 练习
2 函数式接口
2.1 介绍
英文称为Functional Interface
其本质是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
核心目标是为了给Lambda表达式的使用提供更好的支持,进一步达到函数式编程的目标,可通过运用函数式编程极大地提高编程效率。
其可以被隐式转换为 lambda 表达式。
2.2 特点
函数式接口是仅制定一个抽象方法的接口
可以包含一个或多个静态或默认方法
专用注解即@FunctionalInterface 检查它是否是一个函数式接口,也可不添加该注解
如果有两个或以上 抽象方法,就不能当成函数式接口去使用,也不能添加@FunctionalInterface这个注解
如果只有一个抽象方法,那么@FunctionalInterface注解 加不加 都可以当做函数式接口去使用
2.3 代码实现
2.3.1 无参情况
public class FunInterface_01 {
// 自定义静态方法,接收接口对象
public static void call(MyFunctionInter func) {
// 调用接口内的成员方法
func.printMessage();
}
public static void main(String[] args) {
// 第一种调用 : 直接调用自定义call方法,传入函数
FunInterface_01.call(() -> {
System.out.println("HelloWorld!!!");
});
// 第二种调用 : 先创建函数对象,类似于实现接口的内部类对象
MyFunctionInter inter = () -> {
System.out.println("HelloWorld2!!!!");
};
// 调用这个实现的方法
inter.printMessage();
}
}
// 函数式接口
@FunctionalInterface
interface MyFunctionInter {
void printMessage();
}
演示示例:_01_FunInterface.java
2.3.2 有参情况
public class FunInterface_02 {
// 自定义静态方法,接收接口对象
public static void call(MyFunctionInter_02 func, String message) {
// 调用接口内的成员方法
func.printMessage(message);
}
public static void main(String[] args) {
// 调用需要传递的数据
String message = "有参函数式接口调用!!!";
// 第一种调用 : 直接调用自定义call方法,传入函数,并传入数据
FunInterface_02.call((str) -> {
System.out.println(str);
}, message);
// 第二种调用 : 先创建函数对象,类似于实现接口的内部类对象
MyFunctionInter_02 inter = (str) -> {
System.out.println(str);
};
// 调用这个实现的方法
inter.printMessage(message);
}
}
// 函数式接口
@FunctionalInterface
interface MyFunctionInter_02 {
void printMessage(String message);
}
演示示例:_02_FunInterface.java
2.4 JDK自带常用的函数式接口
2.4.1 Supplier<T>接口
Supplier<T>接口 代表结果供应商,所以有返回值,可以获取数据
有一个get方法,用于获取数据
public class _03_JdkOwn_01 {
private static String getResult(Supplier<String> function) {
return function.get();
}
public static void main(String[] args) {
// 1
String before = "张三";
String after = "你好";
// 把两个字符串拼接起来
System.out.println(getResult(() -> before + after));
// 2 //创建Supplier容器,声明为_03_JdkOwn类型
// 此时并不会调用对象的构造方法,即不会创建对象
Supplier<_03_JdkOwn_01> sup = _03_JdkOwn_01::new;
_03_JdkOwn_01 jo1 = sup.get();
_03_JdkOwn_01 jo2 = sup.get();
}
public _03_JdkOwn_01() {
System.out.println("构造方法执行了");
}
}
演示示例:_03_JdkOwn_01.java
2.4.2 Consumer<T>接口
Consumer<T>接口 消费者接口所以不需要返回值
有一个accept(T)方法,用于执行消费操作,可以对给定的参数T 做任意操作
public class _04_JdkOwn_02 {
private static void consumeResult(Consumer<String> function, String message) {
function.accept(message);
}
public static void main(String[] args) {
// 传递的参数
String message = "消费一些内容!!!";
// 调用方法
consumeResult(result -> {
System.out.println(result);
}, message);
}
}
演示示例:_04_JdkOwn_02.java
2.4.3 Function<T,R>接口
Function<T,R>接口 表示接收一个参数并产生结果的函数
顾名思义,是函数操作的
有一个R apply(T)方法,Function中没有具体的操作,具体的操作需要我们去为它指定,因此apply具体返回的结果取决于传入的lambda表达式
public class _05_JdkOwn_03 {
// Function<参数, 返回值>
public static void convertType(Function<String, Integer> function,
String str) {
int num = function.apply(str);
System.out.println(num);
}
public static void main(String[] args) {
// 传递的参数
String str = "123";
// s是说明需要传递参数, 也可以写 (s)
convertType(s -> {
int sInt = Integer.parseInt(s);
return sInt;
}, str);
}
}
演示示例:_05_JdkOwn_03.java
2.4.4 Predicate<T>接口
Predicate<T>接口 断言接口
就是做一些判断,返回值为boolean
有一个boolean test(T)方法,用于校验传入数据是否符合判断条件,返回boolean类型
public class _06_JdkOwn_04 {
// 自定义方法,并且 Predicate 接收String字符串类型
public static void call(Predicate<String> predicate, String isOKMessage) {
boolean isOK = predicate.test(isOKMessage);
System.out.println("isOK吗:" + isOK);
}
public static void main(String[] args) {
// 传入的参数
String input = "ok";
call((String message) -> {
// 不区分大小写比较,是ok就返回true,否则返回false
if (message.equalsIgnoreCase("ok")) {
return true;
}
return false;
}, input);
}
}
3 方法引用和构造器调用
3.1 对象调用成员\
3.2 类名调用静态
3.3 类名调用成员
3.4 构造方法调用
3.5 数组引用
4 Stream API
4.1 概念说明
数据渠道、管道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算 即一组用来处理数组,集合的API。
4.2 特点
Stream 不是数据结构,没有内部存储,自己不会存储元素。
Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
不支持索引访问。
延迟计算
支持并行
很容易生成数据或集合
支持过滤,查找,转换,汇总,聚合等操作。
4.3 应用场景
流式计算处理,需要延迟计算、更方便的并行计算
更灵活、简洁的集合处理方式场景
4.4 代码实现
4.4.1 运行机制
Stream分为源source,中间操作,终止操作。
流的源可以是一个数组,集合,生成器方法,I/O通道等等。
一个流可以有零个或多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用,一个流只会有一个终止操作。
中间操作也称为转换算子-transformation
Stream只有遇到终止操作,它的数据源会开始执行遍历操作。
终止操作也称为动作算子-action
因为动作算子的返回值不再是 stream,所以这个计算就终止了
只有碰到动作算子的时候,才会真正的计算
4.4.2 创建流的方式