java–基础–25–函数式接口
代码
https://gitee.com/DanShenGuiZu/learnDemo/tree/mysql_mybaties_DB/jdk8-learn
1、函数式接口定义
- 有且仅有一个抽象方法的接口
2、@FunctionalInterface
- 放在接口定义的上方,表示该接口是函数式接口
- 接口有且仅有一个抽象方法
- 定义函数式接口的时候,@FunctionalInterface是可选的,就算不写这个注解,只要保证满足函数式接口定义的条件,也照样是函数式接口。
2.1、常用的函数式接口
- Supplier接口
- Consumer接口
- Predicate接口
- Function接口
2.2、案例
2.2.1、函数式接口作为方法的参数
public class Demo1 {
public static void main(String[] args) {
System.out.println("-----函数式接口作为方法的参数----");
method((String s) -> {
System.out.println(s);
});
}
public static void method(Toshow toshow) {
toshow.toSee("小明");
}
interface Toshow {
void toSee(String userName);
}
}
2.2.2、函数式接口作为方法的返回值
public class Demo2 {
public static void main(String[] args) {
Toshow method = method();
method.toSee("小苗");
}
public static Toshow method() {
// // 匿名内部类实现
// return new Toshow() {
// @Override
// public void toSee(String userName) {
// System.out.println(userName);
// }
// };
return (String s) -> {
System.out.println(s);
};
}
interface Toshow {
void toSee(String userName);
}
}
3、Supplier<T>
3.1、介绍
package java.util.function;
/**
* 表示结果的 supplier
* 不要求每次调用supplier时都返回新的或不同的结果
* @param <T> 表示 Supplier 提供的结果类型
*
*/
@FunctionalInterface
public interface Supplier<T> {
/**
* 返回结果
* 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
*/
T get();
}
- 这个接口 用于转换结果类型,结果类型是
<T>
- 这个接口 被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用
3.2、案例
3.2.1、案例1
package fei.zhou.lambdalearn.demo7.supplier;
import java.util.function.Supplier;
public class Test {
public static void main(String[] args) {
String s = getString(() -> {
return "小苗";
});
System.out.println(s);
System.out.println("---------------");
Integer i = getInteger(() -> 30);
System.out.println(i);
}
//定义一个方法,返回一个整数数据
private static Integer getInteger(Supplier<Integer> sup) {
return sup.get();
}
//定义一个方法,返回一个字符串数据
private static String getString(Supplier<String> sup) {
return sup.get();
}
}
输出:
小苗
---------------
30
3.2.2、案例2
package fei.zhou.lambdalearn.demo7.supplier;
import java.util.function.Supplier;
// 用于返回一个int数组中的最大值
public class Test2 {
public static void main(String[] args) {
// 定义一个int数组
int[] arr = {1, 2, 13, 4, 5};
int maxValue = getMax(() -> {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
});
System.out.println(maxValue);
}
// 返回一个int数组中的最大值
private static int getMax(Supplier<Integer> sup) {
return sup.get();
}
}
输出:
13
4、Consumer<T>
4.1、介绍
/**
*
* 表示接受单个输入参数但不返回结果的操作
*
* @param <T> 操作输入的类型
*
*/
@FunctionalInterface
public interface Consumer<T> {
/**
* @param t 输入单个参数,对给定的参数执行此操作
*/
void accept(T t);
/**
* 返回一个组合的Consumer,该Consumer先执行原始的Consumer操作,然后按照从左到右的顺序执行给定的andThen操作。
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
被称为消费型接口,它消费的数据类型由泛型指定。
4.2、案例
4.2.1、案例
public class Demo3 {
public static void main(String[] args) {
operatorString("ABC", (String s) -> {
System.out.println(s.toLowerCase());
});
System.out.println("-----------");
operatorString("ABC", (String s) -> {
System.out.println(s + "转小写:" + s.toLowerCase());
}, (String s) -> {
System.out.println("倒序:" + new StringBuilder(s).reverse().toString());
});
}
// 定义一个方法,用不同的方式消费同一个字符串数据两次
private static void operatorString(String name, Consumer<String> con1, Consumer<String> con2) {
// con1.accept(name);
// con2.accept(name);
con1.andThen(con2).accept(name);
}
// 定义一个方法,消费一个字符串数据
private static void operatorString(String name, Consumer<String> con) {
con.accept(name);
}
}
输出:
abc
-----------
ABC转小写:abc
倒序:CBA
4.2.2、案例2
1. String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33"};
2. 字符串数组中有多条信息,请按照格式:"姓名:XX,年龄:XX"的格式将信息打印出来
要求:
把打印姓名的动作作为第一个Consumer接口的Lambda实例
把打印年龄的动作作为第二个Consumer接口的Lambda实例
将两个Consumer接口按照顺序组合到一起使用
package fei.zhou.lambdalearn.demo7.consumer;
import java.util.function.Consumer;
/*
String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33"};
字符串数组中有多条信息,请按照格式:"姓名:XX,年龄:XX"的格式将信息打印出来
要求:
把打印姓名的动作作为第一个Consumer接口的Lambda实例
把打印年龄的动作作为第二个Consumer接口的Lambda实例
将两个Consumer接口按照顺序组合到一起使用
*/
public class Test2 {
public static void main(String[] args) {
String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33"};
printInfo(strArray,
(String str) -> {
String name = str.split(",")[0];
System.out.print("姓名:" + name);
},
(String str) -> {
int age = Integer.parseInt(str.split(",")[1]);
System.out.println(",年龄:" + age);
});
}
private static void printInfo(String[] strArray, Consumer<String> con1, Consumer<String> con2) {
for (String str : strArray) {
con1.andThen(con2).accept(str);
}
}
}
输出:
姓名:林青霞,年龄:30
姓名:张曼玉,年龄:35
姓名:王祖贤,年龄:33
5、Predicate<T>
5.1、介绍
/**
* @param <T> 输入类型
*/
@FunctionalInterface
public interface Predicate<T> {
/**
* 具体过滤操作 需要被子类实现.
* 用来处理参数T是否满足要求,可以理解为 条件A
*/
boolean test(T t);
/**
* 调用当前Predicate的test方法之后再去调用other的test方法,相当于进行两次判断
* 可理解为 条件A && 条件B
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
/**
* 对当前判断进行"!"操作,即取非操作,可理解为 ! 条件A
*/
default Predicate<T> negate() {
return (t) -> !test(t);
}
/**
* 对当前判断进行"||"操作,即取或操作,可以理解为 条件A ||条件B
*/
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
/**
* 对当前操作进行"="操作,即取等操作,可以理解为 A == B
*/
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
/**
* 对negate方法的加强,不许target为null
*/
@SuppressWarnings("unchecked")
static <T> Predicate<T> not(Predicate<? super T> target) {
Objects.requireNonNull(target);
return (Predicate<T>)target.negate();
}
}
Predicate<T>
接口通常用于判断参数是否满足指定的条件
5.2、案例
5.2.1、案例1
package fei.zhou.lambdalearn.demo7.predicate;
import java.util.function.Predicate;
public class Test {
public static void main(String[] args) {
boolean b1 = checkString("A", (String s) -> {
return s.equals("A");
});
System.out.println("b1:" + b1);
boolean b2 = checkString("A", (String s) -> {
return s.equals("B");
});
System.out.println("b2:" + b2);
}
// 逻辑非操作
private static boolean checkString(String s, Predicate<String> pre) {
// return pre.test(s);
// return !pre.test(s);
return pre.negate().test(s);
}
}
输出:
b1:false
b2:true
5.2.2、案例2
package fei.zhou.lambdalearn.demo7.predicate;
import java.util.function.Predicate;
public class Test2 {
public static void main(String[] args) {
boolean b1 = checkString2("A", (String s) -> {
return s.equals("A");
}, (String s) -> {
return s.equals("B");
});
System.out.println("b1:" + b1);
boolean b2 = checkString3("A", (String s) -> {
return s.equals("A");
}, (String s) -> {
return s.equals("B");
});
System.out.println("b2:" + b2);
}
// 逻辑与运算
private static boolean checkString2(String s, Predicate<String> pre1, Predicate<String> pre2) {
return pre1.and(pre2).test(s);
}
// 逻辑或运算
private static boolean checkString3(String s, Predicate<String> pre1, Predicate<String> pre2) {
return pre1.or(pre2).test(s);
}
}
输出:
b1:false
b2:true
5.2.3、案例3
1. String[] strArray = {"林青霞,30", "柳岩,34", "张曼玉,35", "貂蝉,31", "王祖贤,33"};
2. 字符串数组中有多条信息,请通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中,并遍历ArrayList集合
3. 要求:同时满足如下要求
1:姓名长度大于2
2:年龄大于33
4. 分析:
1:有两个判断条件,所以需要使用两个Predicate接口,对条件进行判断
2:必须同时满足两个条件,所以可以使用and方法连接两个判断条件
package fei.zhou.lambdalearn.demo7.predicate;
import java.util.ArrayList;
import java.util.function.Predicate;
public class Test3 {
public static void main(String[] args) {
String[] strArray = { "林青霞,30", "柳岩,34", "张曼玉,35", "貂蝉,31", "王祖贤,33" };
ArrayList<String> array = myFilter(strArray,
s -> s.split(",")[0].length() > 2,
s -> Integer.parseInt(s.split(",")[1]) > 33);
for (String str : array) {
System.out.println(str);
}
}
// 通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中
private static ArrayList<String> myFilter(String[] strArray, Predicate<String> pre1, Predicate<String> pre2) {
// 定义一个集合
ArrayList<String> array = new ArrayList<>();
// 遍历数组
for (String str : strArray) {
if (pre1.and(pre2).test(str)) {
array.add(str);
}
}
return array;
}
}
输出:
张曼玉,35
6、Function<T,R>
6.1、介绍
T:输入参数,R:返回结果
@FunctionalInterface
public interface Function<T, R> {
/**
* 输入参数T,经过该函数处理得到R。
*/
R apply(T t);
/**
* 此函数有两个参数先将传进来的这个参数传入到before这个函数里面进行处理一下,然后before这个函数的返回结果再作为一个参数传递给外面的这个函数。
* 若before为空,则会抛出异常。
*/
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**
* 参数结构和compose雷同。但是应用方式是相反的。
* 这个是先将参数应用到外层函数,然后得到的结果再传入after进行处理得到结果
*/
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
*
* 返回这个函数的参数。
*/
static <T> Function<T, T> identity() {
return t -> t;
}
}
Function<T,R>
通常用于对参数进行处理,转换,然后返回一个新的值。
6.2、案例
6.2.1、案例1
package fei.zhou.lambdalearn.demo7.function;
import java.util.function.Function;
public class Test {
public static void main(String[] args) {
System.out.println("--------把一个字符串转换int类型,在控制台输出----------");
convert("100", s -> Integer.parseInt(s));
System.out.println("--------把一个int类型的数据加上一个整数之后,转为字符串在控制台输出----------");
convert(100, i -> String.valueOf(i + 566));
System.out.println("--------把一个字符串转换int类型,把int类型的数据加上一个整数之后,转为字符串在控制台输出----------");
convert("100", s -> Integer.parseInt(s), i -> String.valueOf(i + 566));
}
// 把一个字符串转换int类型,在控制台输出
private static void convert(String s, Function<String, Integer> fun) {
int i = fun.apply(s);
System.out.println(i);
}
// 把一个int类型的数据加上一个整数之后,转为字符串在控制台输出
private static void convert(int i, Function<Integer, String> fun) {
String s = fun.apply(i);
System.out.println(s);
}
// 把一个字符串转换int类型,把int类型的数据加上一个整数之后,转为字符串在控制台输出
private static void convert(String s, Function<String, Integer> fun1, Function<Integer, String> fun2) {
// Integer i = fun1.apply(s);
// String ss = fun2.apply(i);
// System.out.println(ss);
String ss = fun1.andThen(fun2).apply(s);
System.out.println(ss);
}
}
输出:
--------把一个字符串转换int类型,在控制台输出----------
100
--------把一个int类型的数据加上一个整数之后,转为字符串在控制台输出----------
666
--------把一个字符串转换int类型,把int类型的数据加上一个整数之后,转为字符串在控制台输出----------
666
6.2.2、案例2
1. String s = "林青霞,30";
2. 请按照我指定的要求进行操作:
1. 将字符串截取得到数字年龄部分
2. 将上一步的年龄字符串转换成为int类型的数据
3. 将上一步的int数据加70,得到一个int结果,在控制台输出
3. 请通过Function接口来实现函数拼接
package fei.zhou.lambdalearn.demo7.function;
import java.util.function.Function;
public class Test2 {
public static void main(String[] args) {
String s = "林青霞,30";
convert(s,
(String ss) -> {
return s.split(",")[1];
},
(String ss) -> {
return Integer.parseInt(ss);
},
(Integer i) -> {
return i + 70;
});
}
private static void convert(String s, Function<String, String> fun1, Function<String, Integer> fun2,
Function<Integer, Integer> fun3) {
int i = fun1.andThen(fun2).andThen(fun3).apply(s);
System.out.println(i);
}
}
输出:
100