本帖最后由 小石姐姐 于 2018-12-6 17:06 编辑
day12 函数式接口 今日内容
自定义函数式接口
@FunctionalInterface 注解
Lambda表达式:
Lambda表达式的"延迟执行"的特点
函数式接口作为方法的"参数"和"返回值类型"
常用函数式接口
Supplier: 生产型函数式接口 获取值
Consumer: 消费型函数式接口 使用值
Predicate: 条件判断型函数式接口 判断值
Function: 转换型函数式接口 转换值
``` 函数式接口
函数式接口概念, 自定义函数式接口知识点:
什么是函数式接口
如何自己定义一个函数式接口
@FunctionalInterface 注解有什么作用
```总结:
函数式接口: JDK 8 新特性
有且仅有一个抽象方法的接口, 适用于函数式编程场景的接口
(默认方法, 静态方法, 私有方法, 与 java.lang.Object 类中定义相同的抽象方法, 都不算作抽象方法)
自定义函数式接口:
接口中有且只有一个抽象方法@FunctionalInterface的作用:
在接口上使用, 检测当前的接口是否为函数式接口
```补充:
// 格式
修饰符 interface 接口名称 {
public abstract 返回值类型 方法名称(可选参数信息);
// 其他非抽象方法内容
}// 示例
[Java] 纯文本查看 复制代码 @FunctionalInterface
public interface MyFunctionalInterface {
void method();
}
``` 函数式接口的使用知识点:```
定义了函数式接口后, 如何使用它
```总结:
函数式接口的使用:
作为方法的参数类型, 传递Lambda表达式, 代替匿名内部类方式
```补充:
public static void method(Animal a) { // 传递实现类对象 Animal a = new Cat();
a.eat();
}public static void method(Runnable r) { // 传递实现类对象 Runnable r = new Runnable(){}
new Thead(r).start();
}
``` 函数式编程
性能浪费的日志案例知识点:```
演示代码的方法中, 传递的字符串参数是否需要先拼接, 才能传入方法内部
```总结:
日志: 就是存储程序运行信息的文本文件.
我们平时打印输出一些信息是在控制台上, 如果将这些信息写入文本文件, 这些文件就是日志
[AppleScript] 纯文本查看 复制代码 public static void showLog(int level, String message) {
if (level == 1) {
System.out.println(message);
}
}
showLog(2, s1 + s2 + s3);
// 先拼接s1+s2+s3出结果"helloworldjava", 然后才执行方法内部的判断
// 相当于方法不需要执行, 但仍然在拼接字符串时浪费了一些性能
```补充:``` 使用Lambda延迟执行的特性优化日志案例知识点:```
使用Lambda实现相同功能, 能否提高效率
```总结:
Lambda具有"延迟执行"的特点:
传递Lambda对象, 只有当符合执行条件时, 才会执行代码
[Java] 纯文本查看 复制代码 @FunctionalInterface
interface MessageBuilder {
String buildMessage();
} public static void showLog(int level, MessageBuilder builder) { // 传递实现类对象
if (level == 1) {
String s = builder.buildMessage();
System.out.println(s);
}
}
showLog(1, new MessageBuilder(){
@Override
public String buildMessage() {
return s1 + s2 + s3;
}
});
showLog(2, () -> s1+s2+s3);
// 传递Lambda对象, 即MessageBuilder实现类对象进方法
// 判断2和1不相等, 所以不会执行builder.buildMessage()
// 从而也不会执行重写方法中的s1+s2+s3
// 避免了无意义的性能浪费
```补充:``` 5分钟练习: 对比Lambda和普通方式执行效率
需求:
定义函数式接口 MessageBuilder, 使用@FunctionalInterface注解修饰
定义抽象方法用于拼接字符串: String buildMessage();
定义测试类:
定义方法模拟拼接大量字符串:
[AppleScript] 纯文本查看 复制代码 public static String getString() {
// 模拟拼接字符串的耗时
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String s1 = "hello";
String s2 = "world";
String s3 = "java";
return s1 + s2 + s3;
}
定义方法: public static void showLog(int level, String message)
方法内部判断如果level==1, 则打印输出message
定义方法: public static void showLogLambda(int level, MessageBuilder builder)
方法内部判断如果level==1, 则打印输出builder.buildMessage()返回的字符串
定义main方法:
调用 showLog(2, getString()), 在方法调用前后获取毫秒值, 相减得出执行时间, 打印出来
调用 showLogLambda(2, ()->getString());在方法调用前后获取毫秒值, 相减得出执行时间, 打印出来
```代码:
[AppleScript] 纯文本查看 复制代码 public interface MessageBuilder {
// 用于拼接字符串的方法, 怎么拼, 需要我们传递Lambda来实现
String buildMessage();
}public class Test {
// 模拟拼接大量字符串的方法:
public static String getString() {
// 模拟拼接字符串的耗时
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String s1 = "hello";
String s2 = "world";
String s3 = "java";
return s1 + s2 + s3;
}
// 普通方式
public static void showLog(int level, String message) {
if (level == 1) {
System.out.println(message);
}
}
// 使用Lambda的延迟执行特性
public static void showLogLambda(int level, MessageBuilder builder) {
if (level == 1) {
String s = builder.buildMessage();
System.out.println(s);
}
}
public static void main(String[] args) {
// 调用普通方法
long start1 = System.currentTimeMillis();
showLog(2, getString());
long end1 = System.currentTimeMillis();
System.out.println("普通方式耗时:" + (end1-start1));
// 调用Lambda延迟执行的方法
long start2 = System.currentTimeMillis();
showLogLambda(2, ()->getString());
long end2 = System.currentTimeMillis();
System.out.println("延迟执行方式耗时:" + (end2-start2));
}
}
```
使用Lambda表达式作为方法参数知识点:
当一个方法的参数是一个函数式接口时, Lambda表达式方式是否比匿名内部类方式简单
... startThread(Runnable r){ // submit(Runnable r)
new Thread(r).start();
}
```总结:
当一个方法的参数是一个函数式接口时, 可以使用Lambda表达式传递该参数, 简化匿名内部类的代码
```补充:``` 5分钟练习: 函数式接口作为方法参数
需求:
定义方法, 用来快速开启线程执行一个任务: public static void startThread(Runnable r)
方法内部创建一个线程对象, 并将任务传递, 开启线程: new Thread(r).start();
在main方法中调用startThread()方法, 使用Lambda表达式方式, 传入一个任务, 任务中打印线程名+"线程启动了"
```代码:
[AppleScript] 纯文本查看 复制代码 public class Test {
public static void main(String[] args) {
// 匿名内部类方式调用方法传递参数
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程启动了");
}
});
[AppleScript] 纯文本查看 复制代码 // Lambda标准格式传递参数
startThread(()->{
System.out.println(Thread.currentThread().getName() + "线程启动了");
}); // Lambda省略格式传递参数
startThread(()->System.out.println(Thread.currentThread().getName() + "线程启动了"));
} // 练习调用参数是函数式接口的方法, 可以向参数传递Lambda表达式
public static void startThread(Runnable r) {
new Thread(r).start();
}
}`
`` 使用Lambda表达式作为方法返回值知识点:
接口: 可以作为方法的参数类型, 还可以作为方法的返回值类型
当一个方法的返回值是一个函数式接口时, Lambda表达式方式是否比匿名内部类方式简单
[AppleScript] 纯文本查看 复制代码 public static Comparator<String> getComparator(){
return new Comparator<String>(){
@Override
public int compare(String o1, String o2) {
// 编写比较的规则 升序
return o1.length()-o2.length();
}
};
}
```总结:
当一个方法的返回值是一个函数式接口时, 可以返回Lambda表达式, 简化匿名内部类的代码
```补充:``` 5分钟练习: 使用Lambda表达式作为返回值
需求:
定义方法, 用于获取一个比较器对象: public static Comparator<String> getComparator()
方法内部使用Lambda表达式作为Comparator接口的返回值, 比较规则是:
第二个字符串参数的长度 - 第一个字符串参数的长度
在main方法中
定义字符串数组: {"aaa", "b", "cccccc", "ddddddddddd"}
调用 getComparator() 方法获取比较器对象
调用 Arrays.sort(数组, 比较器) 方法, 将字符串数组排序, 然后打印出来
```代码:
[AppleScript] 纯文本查看 复制代码 public class Test {
// 获取字符串比较器的方法
public static Comparator<String> getComparator() {
// 使用匿名内部类方式
/*return new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.length() - o1.length(); // 降序
}
};*/ // Lambda标准格式
/*return (String o1, String o2)->{
return o2.length() - o1.length(); // 降序
};*/ // Lambda省略格式
return (o1, o2)->o2.length() - o1.length(); // 按照字符串长度降序
} public static void main(String[] args) {
String[] arr = {"aaa", "b", "cccccc", "ddddddddddd"}; System.out.println("排序前:" + Arrays.toString(arr));
Arrays.sort(arr, getComparator());
System.out.println("排序后:" + Arrays.toString(arr));
}
}
``` 常用函数式接口
Java中提供的常用 函数式接口:
Supplier<T>: 生产型函数式接口 获取值 a和b的和, 获取数组最大值, 获取一个Person对象
Consumer<T>: 消费型函数式接口 使用值 给它一个String让他打印, 给它一个对象
Predicate<T>: 条件判断型函数式接口 判断值 判断字符串长度是否大于5
Function<T, R>: 转换型函数式接口 转换值 给它一个String转换为Integer "123"->123
``` Supplier生产型函数式接口知识点:
JDK 提供的函数式接口在哪个包中
Supplier<T> 接口有什么作用
```总结:
java.util.function.Supplier<T>函数式接口: 生产型函数式接口
// 抽象方法
T get(): 用于获取一个对象或值.
至于获取什么值, 怎么获取, 需要我们根据应用场景编写Lambda来实现
```补充:
[AppleScript] 纯文本查看 复制代码 public class Test {
public static void main(String[] args) {
// 调用方法
String s = getString( ()->"赵丽颖" );
System.out.println(s); // 赵丽颖
// 相当于
getString(new Supplier<String>(){
@Override
public String get() {
return "赵丽颖";
}
});
}
// 定义方法: 用来获取一个字符串 参数: 获取字符串的方式(代码)
public static String getString(Supplier<String> sup) { // 接口实现类对象
return sup.get();
}
}
``` Supplier生产型函数式接口练习: 求数组最大值
5分钟练习: 使用Supplier接口求数组最大值
需求:
使用Supplier接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值
定义测试类:
定义方法, 用于获取数组中的最大值: public static int getMax(Supplier<Integer> sup)
方法内部直接调用sup对象的 get() 方法获取得到的结果, 并return
定义main方法:
方法中定义数组: {100, 0, -50, 88, 99, 33, -30}
调用 getMax() 方法, 方法内部传递Supplier接口的Lambda表达式
表达式中编写获取数组最大值的代码
```代码:
[Java] 纯文本查看 复制代码 public class Test { // 方法的作用: 获取最大值 至于怎么获取, 获取什么的最大值, 需要我们传递Lambda表达式来实现
// 参数的作用: 获取最大值的方式(代码)
public static int getMax(Supplier<Integer> sup) {
return sup.get();
} public static void main(String[] args) {
int[] arr = {100, 0, -50, 88, 99, 33, -30}; // 调用方法来获取数组中的最大值, 怎么获取呢? 我们来传递Lambda表达式实现 // 一开始不熟悉抽象方法的参数和返回值类型, 可以先写匿名内部类, 然后改写为Lambda
/*int maxValue = getMax(new Supplier<Integer>() {
@Override
public Integer get() {
int max = 0;
for (int i : arr) {
if (i > max) {
max = i;
}
}
return max;
}
});*/ // Lambda方式
int maxValue = getMax(()->{
int max = 0;
for (int i : arr) {
if (i > max) {
max = i;
}
}
return max;
}); System.out.println("最大值:" + maxValue);
}
}
``` Consumer消费型函数式接口知识点:
Consumer<T> 接口有什么作用
```总结:
java.lang.StringBuilder类: 可变字符序列, 类似于String, 线程不安全效率高
StringBuilder reverse(): 将StringBuilder内部保存的内容反转
String toString(): 转换为String
new StringBuilder("abc").reverse().toString(); -> "cba" "abc" -> "cba"
java.lang.StringBuffer类: 可变字符序列, 类似于String, 线程安全效率低
StringBuffer reverse(): 将StringBuffer内部保存的内容反转
String toString(): 转换为String
java.util.function.Consumer<T>函数式接口: 消费型函数式接口
// 抽象方法
void accept(T t): 用于消费(使用)一个对象或值. 至于怎么消费, 要我们根据应用场景编写Lambda实现
// 默认方法
default Consumer<T> andThen(Consumer<? super T> after): 拼接两个Consumer接口的Lambda对象实现连续操作. 谁写前面, 谁先消费
```补充:
[AppleScript] 纯文本查看 复制代码 public class Test { // 定义方法用来消费一个字符串. 参数是 被消费的字符串 和 消费方式
public static void method(String name, Consumer<String> con){
con.accept(name);
} public static void main(String[] args) {
String name = "赵丽颖"; // 消费这个字符串, 我们的消费方式是 反转字符串
method(name, (String name)->{
// 反转字符串
String reName = new StringBuilder(name).reverse().toString();
System.out.println(reName); // 颖丽赵 });
}
}
``` Consumer消费型函数式接口: 默认方法andThen()知识点:
Consumer<T>接口中的默认方法 Consumer<T> andThen(Consumer<? super T> after) 如何简化多个Consumer的消费
```总结:
java.util.function.Consumer<T>函数式接口: 消费型函数式接口
// 默认方法
default Consumer<T> andThen(Consumer<? super T> after): 拼接两个Consumer接口的Lambda对象实现连续操作. 谁写前面, 谁先消费
```补充:
public class Test { // 定义方法用来消费一个字符串. 参数是 被消费的字符串 和 消费方式1 和 消费方式2
public static void method(String s, Consumer<String> con1, Consumer<String> con2){
// con1.accept(s);
// con2.accept(s);
// 使用andThen简化
con1.andThen(con2).accept(s);
} public static void main(String[] args) {
// 传入两种消费方式
method("Hello",
(t) -> {
System.out.println(t.toUpperCase()); // HELLO
},
(t) -> {
System.out.println(t.toLowerCase()); // hello
});
}
}
``` Consumer消费型接口练习: 字符串拼接输出
5分钟练习: Consumer接口实现字符串拼接输出
需求:
字符串数组String[] array = {"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男"};当中存有多条信息, 请按照格式"姓名:XX。性别:XX。"格式将信息打印出来.
要求:
将打印姓名的动作, 作为第一个Consumer接口的Lambda实例
将打印性别的动作, 作为第二个Consumer接口的Lambda实例
将两个Consumer接口按照顺序"拼接"到一起public class Test {
[AppleScript] 纯文本查看 复制代码 public static void printInfo(String[] arr, Consumer<String> con1, Consumer<String> con2) {
// 补全代码
}
public static void main(String[] args) {
String[] array = {"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男"};
// 调用printInfo方法
}
}
// 最终效果
姓名:迪丽热巴。性别:女。
姓名:古力娜扎。性别:女。
姓名:马尔扎哈。性别:男。
分析:
被消费的字符串s: "迪丽热巴,女"
// 消费方式1
String[] split = s.split(",");
String name = split[0];
System.out.print("姓名:"+name)// 消费方式2
String[] split = s.split(",");
String gender = split[1];
System.out.println("。性别:"+gender+"。")
最终结果: 姓名:迪丽热巴。性别:女。
```代码:
[AppleScript] 纯文本查看 复制代码 public class Test { // 方法的作用: 将一个字符串数组进行消费, 使用2种消费方式
// 参数的作用: 被消费的字符串数组, 消费方式1, 消费方式2
public static void printInfo(String[] arr, Consumer<String> con1, Consumer<String> con2) {
// 遍历字符串数组, 取出每个信息
for (String message : arr) {
// 对每个信息进行2次消费
con1.andThen(con2).accept(message); // 消费这个字符串, 至于怎么消费, 需要我们传递Lambda实现
}
} public static void main(String[] args) {
String[] array = {"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男"}; // 如果直接写Lambda不熟练, 可以先写匿名内部类
printInfo( // 可以将3个参数换行, 便于查看
array,
new Consumer<String>() {
@Override
public void accept(String s) {
// 消费方式1: 提取姓名并按格式打印
String name = s.split(",")[0];
System.out.print("姓名:" + name);
}
},
new Consumer<String>() {
@Override
public void accept(String s) {
// 消费方式2: 提取性别并按格式打印
String age = s.split(",")[1];
System.out.println("。性别:" + age + "。");
}
}); // Lambda方式
printInfo(
array,
message -> {
// 消费方式1: 提取姓名并按格式打印
String name = message.split(",")[0];
System.out.print("姓名:" + name);
},
message -> {
// 消费方式2: 提取性别并按格式打印
String age = message.split(",")[1];
System.out.println("。性别:" + age + "。");
}
);
}
}
```
Predicate条件判断函数式接口知识点:
Predicate<T> 函数式接口有什么作用
```总结:
java.util.function.Predicate<T>函数式接口: 条件接口, 用于判断
// 抽象方法
boolean test(T t): 判断参数传递的对象. 至于怎么判断, 判断什么, 需要我们编写Lambda表达式实现
// 默认方法 (用于连接多个判断条件)
default Predicate<T> and(Predicate<? super T> other): 与 &&
default Predicate<T> or(Predicate<? super T> other): 或 ||
default Predicate<T> negate(): 非, 取相反结果 !
boolean b = 判断方式1.or(判断方式2).and(判断方式3).negate().test("abc")
```补充:
[AppleScript] 纯文本查看 复制代码 public class Test {
// 定义方法用来检测字符串. 参数是 被检测的字符串 和 检测方式
private static boolean checkString(String s, Predicate<String> pre) {
return pre.test(s);
}
public static void main(String[] args) {
String s = "abcde";
boolean b = checkString(s, str -> str.length()>5);
System.out.println(b); // false
}
}
``` Predicate条件判断函数式接口: 默认方法and()知识点:
Predicate接口中的默认方法 and() 如何实现多个条件"与"的判断
```总结:
default Predicate<T> and(Predicate<? super T> other): 与
```补充:
[AppleScript] 纯文本查看 复制代码 public class Test {
// 定义方法用于按照2个条件检测字符串. 参数: 被检测的字符串, 检测条件1, 检测条件2
public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){
//return pre1.test(s) && pre2.test(s);
return pre1.and(pre2).test(s);
// 两个条件必须同时满足
} public static void main(String[] args) {
String s = "abcdef"; boolean b = checkString(
s,
(String str)->{
return str.length()>5; //判断字符串的长度是否大于5
},
(String str)->{
return str.contains("a"); //判断字符串中是否包含a
});
System.out.println(b);
}
}
``` Predicate条件判断函数式接口: 默认方法or(), negate()知识点:
Predicate接口中的默认方法 or() 如何实现多个条件"或"的判断
Predicate接口中的默认方法 negate() 如何实现多个条件"非"的判断
```总结:
default Predicate<T> or(Predicate<? super T> other): 或
default Predicate<T> negate(): 非, 取相反结果
```补充:
// 或
[AppleScript] 纯文本查看 复制代码 public class Test {
// 定义方法用于检测字符串. 参数 被检测的字符串, 检测方式1, 检测方式2
public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){
//return pre1.test(s) || pre2.test(s);
return pre1.or(pre2).test(s);
// 两个条件满足其一即可
} public static void main(String[] args) {
String s = "bc";
boolean b = checkString(
s,
(String str)->{
return str.length()>5; //判断字符串的长度是否大于5
},
(String str)->{
return str.contains("a"); //判断字符串中是否包含a
});
System.out.println(b); // false
}
}// 取反
public class Test {
// 定义方法用于检测字符串. 参数: 被检测字符串, 检测方式
public static boolean checkString(String s, Predicate<String> pre){
//return !pre.test(s);
return pre.negate().test(s);
// 返回相反的结果
} public static void main(String[] args) {
String s = "abc"; boolean b = checkString(
s,
(String str)->{
return str.length()>5; //判断字符串的长度是否大于5,并返回结果
});
System.out.println(b); // true
}
}
``` Predicate条件判断函数式接口练习: 集合信息筛选
5分钟练习: 使用Predicate实现集合信息筛选
需求:
数组当中有多条"姓名+性别"的信息如下, 请通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中, 需要同时满足两个条件:
1. 必须为女生
2. 姓名为4个字public class Test { // 将字符串数组中满足条件的元素过滤到ArrayList集合当中
private static ArrayList<String> filter(String[] arr, Predicate<String> pre1, Predicate<String> pre2) {
// 按照判断方式补全代码
} public static void main(String[] args) {
String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };
// 补全代码, 调用filter()方法
}
}
```代码:
[AppleScript] 纯文本查看 复制代码 public class Test { // 方法的作用: 按照2个判断方式, 过滤一个String[], 并将满足条件的结果放入ArrayList返回
public static ArrayList<String> filter(String[] arr, Predicate<String> pre1, Predicate<String> pre2) {
// 创建一个新集合
ArrayList<String> list = new ArrayList<>();
// 遍历数组, 将满足条件的元素放入集合
for (String s : arr) {
if (pre1.and(pre2).test(s)) { // 至于怎么判断, 需要我们传递Lambda来实现
list.add(s);
}
}
// 返回集合
return list;
}
public static void main(String[] args) {
String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" }; // 调用方法, 匿名内部类方式
ArrayList<String> result1 = filter(
array,
new Predicate<String>() {
@Override
public boolean test(String s) {
// 必须为女生
return s.split(",")[1].equals("女");
}
},
new Predicate<String>() {
@Override
public boolean test(String s) {
// 姓名为4个字
return s.split(",")[0].length() == 4;
}
}
);
System.out.println(result1); // 调用方法, Lambda方式
ArrayList<String> result2 = filter(
array,
s -> s.split(",")[1].equals("女"),
s -> s.split(",")[0].length() == 4
);
System.out.println(result2);
}
}
``` Function转换型函数式接口知识点:
Function<T,R> 有什么作用"a"->
"a"->
"1"->1->10
```总结:
函数 y = f(x)
java.util.function.Function<T,R>: 根据一个 T类型的数据 转换为 另一个R类型的数据
T是 输入(input)的类型
R是 返回结果(result)的类型
有进有出, 所以称为"函数Function"
// 抽象方法
R apply(T t): 将T转换为R. 至于T和R是什么类型, 以及如何转换, 需要传递Lambda表达式实现
// 默认方法
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 拼接多个Function转换
```补充:
[AppleScript] 纯文本查看 复制代码 public class Test { // 定义方法用于将String转换为Integer.
// 参数: 被转换的字符串, 将String转换为Integer的方式
public static void change(String s, Function<String, Integer> fun){
//Integer in = fun.apply(s);
int in = fun.apply(s);
System.out.println(in);
} public static void main(String[] args) {
String s = "1234"; change(
s,
(String str)->{
return Integer.parseInt(str); //把"1234"转换为Integer类型的整数返回
});
//Lambda省略格式
change(s, str->Integer.parseInt(str));
}
}
``` Function转换型函数式接口: 默认方法andThen()知识点:
Function接口中的 andThen() 如何组合多种转换方法
```总结:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 连接多种转换操作, 先做什么, 再做什么
```补充:
[AppleScript] 纯文本查看 复制代码 public class Test {
// 定义方法用于将String转换为Integer, 然后再将Integer转换为String
// 参数: 被转换的字符串, String转Integer的方式, Integer转String的方式
public static void change(String s, Function<String,Integer> fun1, Function<Integer,String> fun2){
String ss = fun1.andThen(fun2).apply(s);
System.out.println(ss);
} public static void main(String[] args) {
String s = "123"; change(
s,
(String str)->{
return Integer.parseInt(str)+10; //把字符串转换为整数+10
},
(Integer i)->{
return i+""; //把整数转换为字符串
}); //Lambda省略格式
change(
s,
str->Integer.parseInt(str)+10,
i->i+""
);
}
}
``` Function转换型函数式接口: 使用Function连续转换
5分钟练习: 使用Function连续转换
需求:
定义方法, 使用Function进行函数模型的拼接, 将 String str = "赵丽颖,20"; 按照顺序执行以下多个操作:
1. 将字符串截取数字年龄部分, 得到字符串 String->String
2. 将上一步的字符串转换成为int类型的数字 String->Integer
3. 将上一步的int数字累加100, 得到结果int数字 Integer->Integer
最后将结果打印出来
[AppleScript] 纯文本查看 复制代码 public class Test {
public static int change(String s, Function<String, String> fun1, Function<String, Integer> fun2, Function<Integer, Integer> fun3) {
// 补全代码
}
public static void main(String[] args) {
String str = "赵丽颖,20";
// 调用change方法
}
}
```代码:
[AppleScript] 纯文本查看 复制代码 public class Test { // 方法作用: 按照步骤将字符串转换
// 参数: 被转换的字符串, 转换方式1, 转换方式2, 转换方式3
public static int change(String s, Function<String, String> fun1, Function<String, Integer> fun2, Function<Integer, Integer> fun3) {
return fun1.andThen(fun2).andThen(fun3).apply(s);
} public static void main(String[] args) {
String str = "赵丽颖,20"; // 匿名内部类方式
int num1 = change(
str,
new Function<String, String>() { // 将字符串截取数字年龄部分, 得到字符串
@Override
public String apply(String s) {
return s.split(",")[1];
}
},
new Function<String, Integer>() { // 将上一步的字符串转换成为int类型的数字
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
},
new Function<Integer, Integer>() { // 将上一步的int数字累加100, 得到结果int数字
@Override
public Integer apply(Integer integer) {
return integer + 100;
}
}
);
System.out.println(num1); // Lambda方式
int num2 = change(
str,
s -> s.split(",")[1],
s -> Integer.parseInt(s),
i -> i + 100
);
System.out.println(num2);
}
}
```--- 今日API
java.util.function.Supplier<T>函数式接口: 生产型函数式接口
// 抽象方法
T get(): 用于获取一个对象或值. 至于获取什么值, 怎么获取, 需要我们根据应用场景编写Lambda来实现
java.util.function.Consumer<T>函数式接口: 消费型函数式接口
// 抽象方法
void accept(T t): 用于消费(使用)一个对象或值. 至于怎么消费, 需要我们根据应用场景编写Lambda来实现
// 默认方法
default Consumer<T> andThen(Consumer<? super T> after): 拼接两个Consumer接口的Lambda对象实现连续操作. 谁写前面, 谁先消费
java.util.function.Predicate<T>函数式接口: 条件接口, 用于判断
// 抽象方法
boolean test(T t): 判断参数传递的对象. 至于怎么判断, 要判断什么, 需要我们编写Lambda表达式来实现
// 默认方法 (用于连接多个判断条件)
default Predicate<T> and(Predicate<? super T> other): 与
default Predicate<T> or(Predicate<? super T> other): 或
default Predicate<T> negate(): 非, 取相反结果
java.util.function.Function<T,R>: 根据一个T类型的数据得到另一个R类型的数据
T称为前置条件, 也就是输入(input)的类型
R称为后置条件, 也就是返回结果(result)的类型
有进有出, 所以称为"函数Function"
// 抽象方法
R apply(T t): 将T转换为R
// 默认方法
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 拼接多个Function转换
``` 今日目标 能够使用@FunctionalInterface注解
@FunctionalInterface注解 检测是否是函数式接口
``` 能够理解Lambda延迟执行的特点
当需要去调用抽象方法时, 才执行传入的Lambda表达式
``` 能够使用Lambda作为方法的参数
方法参数是函数式接口类型时, 才能使用Lambda作为参数
```
能够使用Supplier<T>函数式接口
生产型
获取值T get()
``` 能够使用Consumer<T>函数式接口
消费型
使用值void accept(T t): 消费指定的参数.
Consumer andThen(Consumer c)
``` 能够使用Predicate<T>函数式接口
判断型
判断值boolean test(T t): 判断参数值, 返回判断结果Predicate and(Predicate p)
Predicate or(Predicate p)
Predicate negate()
``` 能够使用Function<T, R>函数式接口
转换型
转换值R apply(T t): 将T转换为RFunction andThen(Function f)
``` |
|