常用的函数式接口
常用函数式接口
- 仅含有一个抽象方法的接口(不是只有一个方法)
- 该接口常与Lambda表达式相联系
- Lambda表达式延迟加载,可避免性能浪费
Supplier -生产型接口
-
java.util.function.Supplier<泛型T> 接口仅包含一个无参的方法:T get(),用来获取一个泛型参数指定类型的对象数据。由于这是一个函数式接口,也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
-
Supplier<>接口被称为生产型接口,指定接口的泛型是什么类型,那么接口的get方法就会生产什么类型的数据,有返回值。
package cn.learn;
import java.util.function.Supplier;
public class function {
//定义一个方法,方法参数传递Supplier<>接口,泛型执行String.get方法就会返回一个String
public static String getString(Supplier<String> stringSupplier){
return stringSupplier.get();
}
public static void main(String[] args) {
//调用getString方法,方法的参数是一个函数式表达接口,所以传递lambda表达式
String str = getString(() ->{
//生产一个字符串,并返回
return "aaa";
});
System.out.println(str);
//优化Lambda表达式
str = getString(() -> "aaa");
System.out.println(str);
}
}
练习:求数组元素最大值
package cn.learn;
import java.util.function.Supplier;
public class function {
public static Integer getMax(Supplier<Integer> stringSupplier){
return stringSupplier.get();
}
public static void main(String[] args) {
//定义一个数组
int[] arr = new int[]{3,55,66,77,88,-5};
//调用getMax方法,使用Lambda表达式简写
int integermax = getMax(() ->{
//获取数组最大值并返回
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]){
max = arr[i];
}
}
return max;
});
/******
//调用getMax方法
getMax(new Supplier<Integer>() {
@Override
public Integer get() {
//获取数组最大值并返回
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
return max;
}
});
*******/
System.out.println(integermax);
}
}
Consumer -消费型接口
-
java.util.function.Consumer<泛型>接口正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定
-
Consumer接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据,无返回值
package cn.learn;
import java.util.function.Consumer;
public class function {
//accept方法接受的数据可以输出、计算等
public static void print(Integer year,Consumer<Integer> age){
age.accept(year);
}
public static void main(String[] args) {
//消费方式:直接输出
print(2018,(year) -> System.out.println("你的出生年是"+year));
//消费方式:反转字符串
print(2018,(year) -> {
String string = year.toString();
String re = new StringBuilder(string).reverse().toString();
System.out.println(re);
});
}
}
-
Consumer方法中的默认方法——andThen
-
如果一个方法的参数和返回值全部是Consumer类型,那么就可以实现:消费数据的时候,首先做一个操作,然后在做一个操作,实现组合,而这个方法就是Consumer接口中的default方法
-
JDK源码
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
注:java.util.Object的requireNonNull静态方法将会在参数为null时主动抛出NullPointerException异常,这就省去编写if语句和抛出空指针异常的麻烦。
-
若想实现组合效果,需要两个Lambda表达式即可,而andThen的语义正是“一步接一步”操作,例如两个步骤组合的情况:
- Consumer<泛型String> con1;
Consumer<泛型String> con2;
String str = "hello";
con1.accept(str);
con2.accept(str);
- Consumer<泛型String> con1;
package cn.learn;
import java.util.function.Consumer;
public class function {
//把两个Consumer接口组合到一起,再对数据进行消费
public static void method(String str,Consumer<String> con1,Consumer<String> con2){
//使用原始方式
con1.accept(str);
con2.accept(str);
}
public static void main(String[] args) {
//原始使用方式,调用method方法,需要传递两个Lambda表达式
method("Hello",(str) -> {
//消费方式:转为大写
System.out.println(str.toUpperCase());
},(str) ->{
//消费方式:转为小写
System.out.println(str.toLowerCase());
});
}
}
- 连接两个接口再进行消费(谁在前,谁先消费),可以改为
con1.andThen(con2).accept(str);
package cn.learn;
import java.util.function.Consumer;
public class function {
//andThen需要两个Consumer接口,可以把两个Consumer接口组合到一起,再对数据进行消费
public static void method(String str,Consumer<String> con1,Consumer<String> con2){
//先使用con1消费数据,再使用con2
con1.andThen(con2).accept(str);
}
public static void main(String[] args) {
//原始使用方式,调用method方法,需要传递两个Lambda表达式
method("Hello",(str) -> {
//消费方式:转为大写
System.out.println(str.toUpperCase());
},(str) ->{
//消费方式:转为小写
System.out.println(str.toLowerCase());
});
}
}
练习:格式化打印信息
package cn.learn;
import java.util.function.Consumer;
public class function {
//使用两个Consumer来消费字符串,泛型为字符数组
public static void method(String[] str,Consumer<String[]> con1,Consumer<String[]> con2){
//先使用con1消费数据,再使用con2
con1.andThen(con2).accept(str);
}
public static void main(String[] args) {
//定义一个字符串数组
String[] person ={"小王,男","大王,女"};
//原始使用方式,调用method方法,需要传递两个Lambda表达式
method(person,(str) -> {
//消费方式:取人名
for (String name:str) {
//取第一个元素
System.out.println(name.split(",")[0]);
}
},(str) ->{
//消费方式:取性别
for (String name:str) {
//取第一个元素
System.out.println(name.split(",")[1]);
}
});
}
}
结果:
小王
大王
男
女
- 另一种写法
package cn.learn;
import java.util.function.Consumer;
public class function {
//使用两个Consumer来消费字符串,泛型为字符数组
public static void method(String[] str,Consumer<String> con1,Consumer<String> con2){
//将遍历写在此处,预防重复造轮子
for (String message:str) {
//先使用con1消费数据,再使用con2
con1.andThen(con2).accept(message);
}
}
public static void main(String[] args) {
//定义一个字符串数组
String[] person ={"小王,男","大王,女"};
//原始使用方式,调用method方法,需要传递两个Lambda表达式
method(person,(message) -> {
//消费方式:取人名
System.out.println(message.split(",")[0]);
},(message) ->{
//消费方式:取性别
System.out.println(message.split(",")[1]);
});
}
}
结果:
小王
男
大王
女
Predicate -判断接口
-
有时候我们需要对某种数据类型的数据进行判断,从而得到一个boolean值的结果,这时可以使用java.util.function.predicate<泛型>接口
-
Predicate接口中含有一个抽象方法:boolean test(T t)。用于条件判断的场景,返回值为布尔值
package cn.learn;
import java.util.function.Predicate;
public class function {
//
public static boolean checkMethod(String str, Predicate<String> pre){
return pre.test(str);
}
public static void main(String[] args) {
String str = "hello";
//对字符串进行校验
boolean check = checkMethod(str,(String str01) ->{
return str01.length()>5;
});
boolean check1 = checkMethod(str,str01 -> str01.length()>3);
System.out.println(check);
System.out.println(check1);
}
}
* 默认方法:and -可以判断多个判断条件和“&&”差不多
```java
package cn.learn;
import java.util.function.Predicate;
public class function {
//
public static boolean checkMethod(String str, Predicate<String> pre1, Predicate<String> pre2){
//等价于return pre1.test(str) && pre2.test(str);
return pre1.and(pre2).test(str);
}
public static void main(String[] args) {
String str = "hello";
//对字符串进行校验
boolean check = checkMethod(str,(String str01) ->{
return str01.length()>3;
},(str01) ->{
return str01.contains("1");
});
System.out.println(check);
}
}
false
- 默认方法:or -可以判断多个判断条件和“||”差不多
package cn.learn;
import java.util.function.Predicate;
public class function {
//
public static boolean checkMethod(String str, Predicate<String> pre1, Predicate<String> pre2){
//等价于return pre1.test(str) || pre2.test(str);
return pre1.or(pre2).test(str);
}
public static void main(String[] args) {
String str = "hello";
//对字符串进行校验
boolean check = checkMethod(str,(String str01) ->{
return str01.length()>3;
},(str01) ->{
return str01.contains("1");
});
System.out.println(check);
}
}
true
- 默认方法:negate -可以判断多个判断条件和“!”差不多
package cn.learn;
import java.util.function.Predicate;
public class function {
//
public static boolean checkMethod(String str, Predicate<String> pre1){
//等价于return !pre1.test(str);
return pre1.negate().test(str);
}
public static void main(String[] args) {
String str = "hello";
//对字符串进行校验
boolean check = checkMethod(str,(String str01) ->{
return str01.length()>3;
});
System.out.println(check);
}
}
false
练习:集合信息筛选
- 将名字为2个字且为女生的字符串选到集合中,注意字符串判断需要用equals方法
package cn.learn;
import java.util.ArrayList;
import java.util.function.Predicate;
public class function {
public static ArrayList<String> filter(String[] str, Predicate<String> pre1, Predicate<String> pre2) {
//放外边,里边会重复申请
ArrayList<String> correct = new ArrayList<>();
//遍历数组
for (String message : str) {
boolean ifCorr = pre1.and(pre2).test(message);
//满足条件的放入集合
if (ifCorr) {
correct.add(message);
}
}
return correct;
}
public static void main(String[] args) {
String[] str = {"小王,女", "大王,男", "小白,男", "王小白,女"};
//对字符串进行筛选,并返回需要的集合
ArrayList<String> list = filter(str, (String str01) -> {
return str01.split(",")[0].length() == 2;
}, (str01) -> str01.split(",")[1].equals("女") );
System.out.println(list);
}
}
[小王,女]
Function -数据类型转换接口
-
java.util.function.Function<T,R>接口用来根据一个数据类型得到另一个数据类型,前者称为前置条件,后者称为后置条件。
-
抽象方法:apply,R apply
,根据类型T的参数获取R型的结果,返回的是另一个类型的值。
package cn.learn;
import java.util.function.Function;
public class function {
public static Integer convert(String str, Function<String,Integer> function){
//返回一个Integer类型
return function.apply(str);
}
public static void main(String[] args) {
String str = "2018";
//调用convert方法转换类型,并用Lambda表达式重写apply方法
Integer strInt = convert(str,(String str01) ->{
return Integer.parseInt(str01);
});
System.out.println(strInt);
}
}
-
默认方法:andThen,用来进行组合操作
-
需求:把字符串转换为Integer类型,把结果进行运算,
再把整型转换回去
package cn.learn;
import java.util.function.Function;
public class function {
public static String convert(String str, Function<String,Integer> fun1,Function<Integer,String> fun2){
//返回一个String类型
return fun1.andThen(fun2).apply(str);
}
public static void main(String[] args) {
String str = "2018";
//调用convert方法转换类型,取出字符串对应的值并进行运算,再转换为String
str = convert(str,str01 ->Integer.parseInt(str01)+10,int01 -> int01.toString());
System.out.println(str);
}
}
2028