- 前置复习: 匿名内部类思想
- 匿名类的用处
- 传递代码块
- 回调
- 匿名类在过滤中的使用
- 一、Lambda表达式
- 1.1、举例Demo
- 1.2、Lambda表达式的出现
- 1.3、Lambda格式及说明
- 1.4、Lambda练习1
- 1.5、Lambda练习2
- 1.6、Lambda练习3
- 1.7、Lambda表达式使用的前提条件
- 1.8、Lambda 和 匿名内部类对比
- 二、函数式(Functional)接口
- 2.1、函数式接口的介绍
- 2.2、Java内置的函数式接口介绍及使用举例
- Supplier 供给型接口 (优化不一定执行的代码)
- Consumer供给型接口 (接收一个元素决定做什么)
- Predicate函数式接口 (让过滤条件更灵活)
- Function(类型转换)
- 三、方法引用与构造器引用
- 3.1、方法引用的使用情况1
- 3.2、方法引用的使用情况2
- 3.3、方法引用的使用情况3
- 3.4、构造器引用与数组引用的使用
- 代码传递
- 回调
- 过滤器
当如果有需求, 我们需要将外部的一段代码
, 在内部执行, 就考虑可以使用匿名类。
package com.other.noname;
/**
* Description:
*
* @date 2022/4/2 20:57
*/
public class Main {
public static void main(String[] args) {
// 现在要计算一段代码的执行时间, 首先需要想到要创建一个工具类TimeUtil
// 首先要想到这一点; 伪代码
// TimeUtil.test(
// // 需要计算时间的代码片段
// int count = 0;
// for (int i = 0; i < 100; i++) {
// count += i;
// }
// )
TimeUtil.test(new TimeUtil.Block() {
@Override
public void execute() {
// 在这里写我们需要执行的代码块
for (int i = 0; i 2;
}
});
filterCollection.forEach(System.out::println);
}
public class FilterUtil {
public interface Filter {
boolean test(T t);
}
public static Collection getFilterCollection(Collection collection, Filter filter) {
List list = new ArrayList();
collection.forEach(item -> {
if (filter.test(item)) {
list.add(item);
}
});
return list;
}
}
一、Lambda表达式
- Lambda 是一个匿名函数,
我们可以把Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)
- 使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
public class LambdaDemo {
public static void main(String[] args) {
//开启一个线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("新线程执行代码");
}
}).start();
}
分析上面代码
- 当我们以
new Thread().start()
的方式启动一个线程时,我们做了如下3件事情:
- 定义了一个没有名字的类(匿名类) – new Thread(Runnable接口)
- 这个类的参数是Runnable 接口
- 我们通过 new Runnable(){…}的方式创建了这个类,并重写了该接口的 run() 方法
- 在这个示例中,其实我们关注的并不是 new Runnable() 这个过程,而是如下2点:
- run() 方法 (参数情况)
- 以及run方法 {…}方法体中执行的代码
- 在以上Demo中,针对使用匿名内部类语法冗余的问题,JDK8推出了 Lambda 表达式。
- Lambda表达式体现的是函数式编程思想,
只需要将要执行的代码放到函数中即可(函数就是类中的方法)
; - Lambda表达式就是一个匿名函数,我们只需要将执行的代码放到 Lambda 表达式中即可。
Lambda省去面向对象的条条框框,Lambda的标准格式由3部分组成:
(参数类型 参数名称) -> {
方法体;
return 返回值;
}
格式说明
- (参数类型 参数名称):(接口方法)重写方法的参数列表部分
- {…}:重写方法的方法体,即要执行的代码部分
- –>:箭头,无实际含义,起到连接参数列表和方法体的作用
Lambda 表达式的省略规则
- 小括号中的参数类型可以省略。
- 如果小括号中只有一个参数,那么可以省略小括号。
- 如果大括号中只有一条语句,那么可以同时省略大括号、return关键字及语句分号。
使用Lambda优化Demo
public class LambdaDemo {
public static void main(String[] args) {
//匿名内部类方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("新线程执行代码了");
}
}).start();
//体验Lambda表达式: () -> {xxxx}, ()无参数是和Runable中run方法的参数对应的
// {xxx}是重写run方法的方法体
new Thread(() ->{
System.out.println("Lambda表达式执行了");
}).start();
}
}
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
1.4、Lambda练习1
import org.junit.Test;
import java.util.Comparator;
/**
* Lambda表达式的使用举例
*/
public class LambdaTest {
@Test
public void test(){
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("长安欢迎您");
}
};
r1.run();
System.out.println("+++++++++++++++++++++++++|");
Runnable r2 = () -> System.out.println("长安欢迎您");
r2.run();
}
@Test
public void test2(){
Comparator c1 = new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int compare1 = c1.compare(8,16);
System.out.println(compare1);
System.out.println("+++++++++++++++++++++++");
//Lambda表达式的写法
// int compare(T o1, T o2);
Comparator c2 = (o1,o2) -> Integer.compare(o1,o2);
int compare2 = c2.compare(28,35);
System.out.println(compare2);
System.out.println("+++++++++++++++++++++++++++");
//方法引用(暂时可以不关注,后面会介绍)
Comparator c3 = Integer :: compare;
int compare3 = c3.compare(28,35);
System.out.println(compare3);
}
}
@FunctionalInterface
public interface Comparator {
int compare(T o1, T o2);
}
1.5、Lambda练习2
import org.junit.Test;
import java.util.ArrayList;
import java.util.function.Consumer;
/**
* Lambda表达式的使用
*
* 1.举例: (o1,o2) -> Integer.compare(o1,o2);
* 2.格式:
* -> :lambda操作符 或 箭头操作符
* ->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)
* ->右边:lambda体 (其实就是重写的抽象方法的方法体)
*
* 3.Lambda表达式的使用:(分为6种情况介绍)
*/
public class LambdaTest1 {
//语法格式一:无参,无返回值
@Test
public void test(){
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("长安欢迎您");
}
};
r1.run();
System.out.println("+++++++++++++++++++++++++|");
Runnable r2 = () -> System.out.println("长安欢迎您");
r2.run();
}
//语法格式二:Lambda 需要一个参数,但是没有返回值。
@Test
public void test2(){
Consumer con = new Consumer() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("善与恶的区别是什么?");
System.out.println("+++++++++++++++++++");
Consumer c1 = (String s) -> {
System.out.println(s);
};
c1.accept("先天人性无善恶,后天人性有善恶。");
}
@FunctionalInterface
public interface Consumer {
void accept(T t);
}
//语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
@Test
public void test3(){
Consumer c1 = (String s) -> {
System.out.println(s);
};
c1.accept("先天人性无善恶,后天人性有善恶。");
System.out.println("---------------------");
Consumer c2 = (s) -> {
System.out.println(s);
};
c2.accept("如果没有邪恶的话我们怎么会知道人世间的那些善良呢?");
}
@Test
public void test4(){
ArrayList list = new ArrayList();//类型推断
int[] arr = {1,2,3};//类型推断
}
}
1.6、Lambda练习3
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
/**
* Lambda表达式的使用
*
* 1.举例: (o1,o2) -> Integer.compare(o1,o2);
* 2.格式:
* -> :lambda操作符 或 箭头操作符
* ->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)
* ->右边:lambda体 (其实就是重写的抽象方法的方法体)
*
* 3.Lambda表达式的使用:(分为6种情况介绍)
*
* 总结:
* ->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略
* ->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字
*/
public class LambdaTest1 {
//语法格式四:Lambda若只需要一个参数时,参数的小括号可以省略
@Test
public void test5(){
Consumer c1 = (s) -> {
System.out.println(s);
};
c1.accept("先天人性无善恶,后天人性有善恶。");
System.out.println("---------------------");
Consumer c2 = s -> {
System.out.println(s);
};
c2.accept("如果没有邪恶的话我们怎么会知道人世间的那些善良呢?");
}
//语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
@Test
public void test6(){
Comparator c1 = new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}
};
System.out.println(c1.compare(15,23));
System.out.println("\\\\\\\\\\\\\\\\\\\\\\\\\\");
Comparator com2 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(com2.compare(16,8));
}
//语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略
@Test
public void test7(){
Comparator c1 = (o1,o2) -> {
return o1.compareTo(o2);
};
System.out.println(c1.compare(16,8));
System.out.println("\\\\\\\\\\\\\\\\\\\\\\\\\\");
Comparator c2 = (o1,o2) -> o1.compareTo(o2);
System.out.println(c2.compare(17,24));
}
@Test
public void test8(){
Consumer c1 = s -> {
System.out.println(s);
};
c1.accept("先天人性无善恶,后天人性有善恶。");
System.out.println("---------------------");
Consumer c2 = s -> System.out.println(s);
c2.accept("如果没有邪恶的话我们怎么会知道人世间的那些善良呢?");
}
}
1.7、Lambda表达式使用的前提条件
方法的参数或局部变量类型必须为接口,才能使用Lambda
- 接口中有且仅有一个抽象方法, DK8中,只有一个抽象方法的接口称为函数式接口,我们就能使用 Lambda。
- 针对一个接口中,是否有大于一个抽象方法?JDK8为我们新增了一个注解:@FunctionalInterface。它能够帮助我们检测这个接口是不是只有一个抽象方法,如果有两个抽象方法,则会报错。
- 1.所需的类型不一样
- 匿名内部类,需要的类型可以使类,抽象类,接口;
- Lambda表达式,需要的类型必须是接口。
- 2.抽象方法的数量不一样
- 匿名内部类所需的接口中抽象方法的数量随意;
- Lambda表达式所需的接口只能有一个抽象方法。
- 3.实现原理不同
- 匿名内部类是在编译后,会形成额外的一个 类名$0 的.class文件
- Lambda 表达式实在程序运行的时候动态生成 .class 文件
/*
* 4.Lambda表达式的本质:作为函数式接口的实例
*
* 5. 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用 @FunctionalInterface 注解,
* 这样做可以检查它是否是一个函数式接口。
*
*/
/**
* 自定义函数式接口
*/
public interface MyInterFace {
void method();
// void method2();
}
- 在
java.util.function
包下定义了Java 8 的丰富的函数式接口 - 简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。
- 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
Consumer
消费型接口Tvoid对类型为T的对象应用操作,包含方法:void accept(T t)
Supplier
供给型接口无T返回类型为T的对象,包含方法:T get()
Function
函数型接口TR对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t)
Predicate
断定型接口Tboolean确定类型为T的对象是否满足某约束,并返回boolean 值。包含方法:boolean test(T t)
BiFunction
T, UR对类型为T,U参数应用操作,返回R类型的结果。包含方法为:R apply(T t,U u)
;UnaryOperator
(Function子接口)TT对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为:T apply(T t)
;BinaryOperator
(BiFunction子接口)T,TT对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为:T apply(T t1,T t2)
;BiConsumer
T,Uvoid对类型为T,U参数应用操作。包含方法为:void accept(Tt,Uu)
BiPredicate
T,Uboolean包含方法为:boolean test(Tt,Uu)
ToIntFunction
Tint计算int
值的函数ToLongFunction
Tlong计算long
值的函数ToDoubleFunction
Tdouble计算double
值的函数IntFunction
intR参数为int
类型的函数LongFunction
longR参数为long
类型的函数DoubleFunction
doubleR参数为double
类型的函数
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* java内置的4大核心函数式接口
*
* 消费型接口 Consumer void accept(T t)
* 供给型接口 Supplier T get()
* 函数型接口 Function R apply(T t)
* 断定型接口 Predicate boolean test(T t)
*/
public class LambdaTest2 {
// ----消费型接口 Consumer void accept(T t)
public void happyTime(double money, Consumer con) {
con.accept(money);
}
@Test
public void test(){
happyTime(30, new Consumer() {
@Override
public void accept(Double aDouble) {
System.out.println("熬夜太累了,点个外卖,价格为:" + aDouble);
}
});
System.out.println("+++++++++++++++++++++++++");
//Lambda表达式写法
happyTime(20, money -> System.out.println("熬夜太累了,吃口麻辣烫,价格为:" + money));
}
// -----供给型接口 Supplier T get()
//根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定
public List filterString(List list, Predicate pre){
ArrayList filterList = new ArrayList();
for(String s : list){
if(pre.test(s)){
filterList.add(s);
}
}
return filterList;
}
@Test
public void test2(){
List list = Arrays.asList("长安","上京","江南","渝州","凉州","兖州");
List filterStrs = filterString(list, new Predicate() {
@Override
public boolean test(String s) {
return s.contains("州");
}
});
System.out.println(filterStrs);
List filterStrs1 = filterString(list,s -> s.contains("州"));
System.out.println(filterStrs1);
}
}
Supplier 供给型接口 (优化不一定执行的代码)
T get();
/**
* Description: 供给型接口
*
* T get();
*
* 有时使用 Supplier 传参,可以避免代码的浪费执行(有必要的时候再执行)
*/
public class SupplierTest {
/*
现在有个需求, 如果第一个字符串不为空, 则返回第一个字符串, 否则返回第二个字符串
*/
public static void main(String[] args) {
System.out.println(getFirstNotEmptyString("Jack", makeString()));
}
public static String getFirstNotEmptyString(String str1, String str2) {
if (str1 != null && str1.length() > 0) return str1;
if (str2 != null && str2.length() > 0) return str2;
return null;
}
private static String makeString() {
System.out.println("makeString");
return String.format("%d %d %d", 1, 2, 3);
}
}
此时发现, 如果第一个参数不为空之后, 还调用了makeString()方法, 明显存在浪费调用; 所以可以使用Supplier来优化
/**
* Description: 供给型接口
*
* T get();
*
* 有时使用 Supplier 传参,可以避免代码的浪费执行(有必要的时候再执行)
*
* @date 2022/4/3 18:58
*/
public class SupplierTest {
/*
现在有个需求, 如果第一个字符串不为空, 则返回第一个字符串, 否则返回第二个字符串
*/
public static void main(String[] args) {
//System.out.println(getFirstNotEmptyString("Jack", makeString()));
System.out.println(getFirseNotEmptyString("Jack", new Supplier() {
@Override
public String get() {
return makeString();
}
}));
//System.out.println(getFirseNotEmptyString("Jack", () -> makeString()));
//System.out.println(getFirseNotEmptyString("Jack", SupplierTest::makeString));
}
// public static String getFirstNotEmptyString(String str1, String str2) {
// if (str1 != null && str1.length() > 0) return str1;
// if (str2 != null && str2.length() > 0) return str2;
// return null;
// }
// 优化
public static String getFirseNotEmptyString(String str1, Supplier supplier) {
if (str1 != null && str1.length() > 0) return str1;
String str2 = supplier.get();
if (str2 != null && str2.length() > 0) return str2;
return null;
}
private static String makeString() {
System.out.println("makeString");
return String.format("%d %d %d", 1, 2, 3);
}
}
// 此时就完成了优化, 延迟了makeString()方法的调用
Consumer供给型接口 (接收一个元素决定做什么)
void accept(T t)
public static void main(String[] args) {
/*
Consumer这个函数式接口, 用来接收我们提供的元素, 具体操作这些元素由调用者来决定
*/
Integer[] nums = {1, 2, 3, 4};
// 比如, 我们要遍历所有元素
for (Integer num : nums) {
System.out.println(num);
}
// 比如, 我们要遍历所有都+100的元素
for (Integer num : nums) {
System.out.println(num + 100);
}
// 上面的代码, 实现了需求, 但是具体对元素的操作是千变万化的, eg: 遍历出偶数/基数元素等,我们还需要再写不同的逻辑进行处理
// 此时可以使用Consumer函数式接口
}
public class ConsumerTest {
public static void main(String[] args) {
/*
Consumer这个函数式接口, 用来接收我们提供的元素, 具体操作这些元素由调用者来决定
*/
Integer[] nums = {1, 2, 3, 4};
// 比如, 我们要遍历所有元素
for (Integer num : nums) {
System.out.println(num);
}
// 比如, 我们要遍历所有都+100的元素
for (Integer num : nums) {
System.out.println(num + 100);
}
System.out.println("--------------------------");
// 上面的代码, 实现了需求, 但是具体对元素的操作是千变万化的, eg: 遍历出偶数/基数元素等,我们还需要再写不同的逻辑进行处理
// 此时可以使用Consumer函数式接口
forEach(nums, System.out::println);
forEach(nums, integer -> System.out.println(integer + 100));
}
// public static void forEach(Integer[] nums, Consumer consumer) {
// if (nums == null || consumer == null) return;
// for (Integer num : nums) {
// consumer.accept(num); // 这里是Consumer的接口方法, 具体的实现方法, 由调用者来决定
// }
// }
// 对上面代码的优化, 变成泛型方法, 增加通用性
public static void forEach(T[] nums, Consumer consumer) {
if (nums == null || consumer == null) return;
for (T num : nums) {
consumer.accept(num); // 这里是Consumer的接口方法, 具体的实现方法, 由调用者来决定
}
}
}
andThen的使用
public static void main(String[] args) {
int[] nums = { 11, 33, 44, 88, 77, 66 };
forEach(nums, (n) -> {
String result = ((n & 1) == 0) ? "偶数" : "奇数";
System.out.println(n + "是" + result);
}, (n) -> {
String result = ((n % 3) == 0) ? "能" : "不能";
System.out.println(n + result + "被3整除");
});
}
static void forEach(int[] nums, Consumer c1, Consumer c2) {
if (nums == null || c1 == null || c2 == null) return;
for (int n : nums) {
// 相当于先执行c1的任务, 然后执行c2的任务, 执行完后进入下一轮循环
c1.andThen(c2).accept(n);
}
}
11是奇数
11不能被3整除
33是奇数
33能被3整除
44是偶数
44不能被3整除
88是偶数
88不能被3整除
77是奇数
77不能被3整除
66是偶数
66能被3整除
Predicate函数式接口 (让过滤条件更灵活)
boolean test(T t);
/**
* Description: 应用常见, 过滤操作
*
* boolean test(T t);
*
* @date 2022/4/3 19:31
*/
public class PredicateTest {
public static void main(String[] args) {
/*
对数组中{11, 22, 33, 44, 55, 66}的偶数用_进行拼接
*/
Integer[] nums = {11, 22, 33, 44, 55, 66};
join(nums, new Predicate() {
@Override
public boolean test(Integer integer) {
return integer % 2 == 0; // 表示integer为偶数的时候, 才进行拼接
}
});
System.out.println("-------------------");
join(nums, item -> item % 2 == 0);
}
public static void join(Integer[] nums, Predicate predicate) {
if (nums == null || predicate == null) return;
for (Integer num : nums) {
if (predicate.test(num)) {
System.out.println(num + "_");
}
}
}
}
Function(类型转换)
R applay(T t);
/**
* Description: Fucntion 类型转换
*
* R apply(T t);
*
*/
public class FunctionTest {
public static void main(String[] args) {
/*
需求, 将传入的字符串数字的数组, 求和
*/
System.out.println(getSum(new String[]{"1", "2", "3"}, new Function() {
@Override
public Integer apply(String s) {
return Integer.valueOf(s);
}
}));
System.out.println(getSum(new String[]{"1", "2", "3"}, Integer::valueOf));
}
public static int getSum(String[] array, Function function) {
if (array == null || function == null) return 0;
int result = 0;
for (String str : array) {
result += function.apply(str);
}
return result;
}
}
三、方法引用与构造器引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
- 方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
- 要求:
实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
- 格式:使用操作符“::” 将类(或对象) 与方法名分隔开来。
- 如下三种主要使用情况:
- 对象::实例方法名
- 类::静态方法名
- 类::实例方法名
1、Employee类
@Data
public class Employee {
private int id;
private String name;
private int age;
private double salary;
}
2、测试类
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 方法引用的使用
*
* 1.使用情境:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
*
* 2.方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以
* 方法引用,也是函数式接口的实例。
*
* 3. 使用格式: 类(或对象) :: 方法名
*
* 4. 具体分为如下的三种情况:
* 情况1 对象 :: 非静态方法
* 情况2 类 :: 静态方法
*
* 情况3 类 :: 非静态方法
*
* 5. 方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的
* 形参列表和返回值类型相同!(针对于情况1和情况2)
*/
public class MethodRefTest {
// 情况一:对象 :: 实例方法
//Consumer中的void accept(T t)
//PrintStream中的void println(T t)
@Test
public void test() {
Consumer c1 = str -> System.out.println(str);
c1.accept("兖州");
System.out.println("+++++++++++++");
PrintStream ps = System.out;
Consumer c2 = ps::println;
c2.accept("xian");
}
//Supplier中的T get()
//Employee中的String getName()
@Test
public void test2() {
Employee emp = new Employee(004,"Nice",19,4200);
Supplier sk1 = () -> emp.getName();
System.out.println(sk1.get());
System.out.println("*******************");
Supplier sk2 = emp::getName;
System.out.println(sk2.get());
}
}
3.2、方法引用的使用情况2
1、Employee类——同上
2、测试类
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Function;
public class MethodRefTest {
// 情况二:类 :: 静态方法
//Comparator中的int compare(T t1,T t2)
//Integer中的int compare(T t1,T t2)
@Test
public void test3() {
Comparator com1 = (t1, t2) -> Integer.compare(t1,t2);
System.out.println(com1.compare(21,20));
System.out.println("+++++++++++++++");
Comparator com2 = Integer::compare;
System.out.println(com2.compare(15,7));
}
//Function中的R apply(T t)
//Math中的Long round(Double d)
@Test
public void test4() {
Function func = new Function() {
@Override
public Long apply(Double d) {
return Math.round(d);
}
};
System.out.println("++++++++++++++++++");
Function func1 = d -> Math.round(d);
System.out.println(func1.apply(14.1));
System.out.println("++++++++++++++++++");
Function func2 = Math::round;
System.out.println(func2.apply(17.4));
}
}
3.3、方法引用的使用情况3
1、Employee类——同上
2、测试类
import org.junit.Test;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Function;
public class MethodRefTest {
// 情况三:类 :: 实例方法 (有难度)
// Comparator中的int comapre(T t1,T t2)
// String中的int t1.compareTo(t2)
@Test
public void test5() {
Comparator com1 = (s1,s2) -> s1.compareTo(s2);
System.out.println(com1.compare("abc","abd"));
System.out.println("++++++++++++++++");
Comparator com2 = String :: compareTo;
System.out.println(com2.compare("abd","abm"));
}
//BiPredicate中的boolean test(T t1, T t2);
//String中的boolean t1.equals(t2)
@Test
public void test6() {
BiPredicate pre1 = (s1, s2) -> s1.equals(s2);
System.out.println(pre1.test("MON","MON"));
System.out.println("++++++++++++++++++++");
BiPredicate pre2 = String :: equals;
System.out.println(pre2.test("MON","MON"));
}
// Function中的R apply(T t)
// Employee中的String getName();
@Test
public void test7() {
Employee employee = new Employee(007, "Ton", 21, 8000);
Function func1 = e -> e.getName();
System.out.println(func1.apply(employee));
System.out.println("++++++++++++++++++++++++");
Function f2 = Employee::getName;
System.out.println(f2.apply(employee));
}
}
3.4、构造器引用与数组引用的使用
格式:ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。
可以把构造器引用赋值给定义的方法,要求构造器参数列表要与接口中抽象方法的参数列表一致!且方法的返回值即为构造器对应类的对象。
1、Employee类——同上
2、测试类
import org.junit.Test;
import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 一、构造器引用
* 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
* 抽象方法的返回值类型即为构造器所属的类的类型
*
* 二、数组引用
* 可以把数组看做是一个特殊的类,则写法与构造器引用一致。
*/
public class MethodRefTest {
//构造器引用
//Supplier中的T get()
//Employee的空参构造器:Employee()
@Test
public void test() {
Supplier sup = new Supplier() {
@Override
public Employee get() {
return new Employee();
}
};
System.out.println("+++++++++++++++++++");
Supplier sk1 = () -> new Employee();
System.out.println(sk1.get());
System.out.println("+++++++++++++++++++");
Supplier sk2 = Employee::new;
System.out.println(sk2.get());
}
//Function中的R apply(T t)
@Test
public void test2() {
Function f1 = id -> new Employee(id);
Employee employee = f1.apply(7793);
System.out.println(employee);
System.out.println("+++++++++++++++++++");
Function f2 = Employee::new;
Employee employee1 = f2.apply(4545);
System.out.println(employee1);
}
//BiFunction中的R apply(T t,U u)
@Test
public void test3() {
BiFunction f1 = (id, name) -> new Employee(id, name);
System.out.println(f1.apply(2513, "Fruk"));
System.out.println("*******************");
BiFunction f2 = Employee::new;
System.out.println(f2.apply(9526, "Bon"));
}
//数组引用
//Function中的R apply(T t)
@Test
public void test4() {
Function f1 = length -> new String[length];
String[] arr1 = f1.apply(7);
System.out.println(Arrays.toString(arr1));
System.out.println("+++++++++++++++++++");
Function f2 = String[]::new;
String[] arr2 = f2.apply(9);
System.out.println(Arrays.toString(arr2));
}
}