文章目录
一.函数式接口是什么?
-
有且只有一个抽象方法的接口
被称为函数式接口,函数式接口适用于函数式编程
的场景,Lambda就是Java中函数式编程的体现,可以使用Lambda表达式创建一个函数式接口的对象
,一定要确保接口中有且只有一个抽象方法
,这样Lambda才能顺利的进行推导。 -
Java 8中专门为函数式接口引入了一个新的注解:·@FunctionalInterface· 。一旦使用该注解来定义接口,
编译器将会·强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错
。但是这个注解不是必须的,只要符合函数式接口的定义,那么这个接口就是函数式接口。
-
函数式接口中只允许有一个
抽象方法
,但是可以有多个static方法和default方法
。
二.自定义函数式接口
@FunctionalInterface
public interface MyFunction {
void print(String s);
}
public class MyFunctionTest {
public static void main(String[] args) {
String text = "试试自定义函数好使不";
printString(text, System.out::print);
}
private static void printString(String text, MyFunction myFunction) {
myFunction.print(text);
}
}
三.常见函数式接口
1.Supplier<T>
: 供给型接口
-
抽象方法:T get(),
无参数,有返回值
。使用时需指定一个泛型来定义参数类型
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * @return a result */ T get(); }
-
练习:求数组最大值
public class SupplierTest { public static void main(String[] args) { fun1(()->{ //执行处理数据逻辑 int arr[] = { 22,33,55,66,44,99,10}; // 计算出数组中的最大值 Arrays.sort(arr); return arr[arr.length-1]; });// } //获取返回数据进行处理 private static void fun1(Supplier<Integer> supplier){ // get() 是一个无参的有返回值的 抽象方法 Integer max = supplier.get(); System.out.println("max = " + max); } }
2.Consumer<T>
:消费型接口
-
抽象方法: void accept(T t),
接收一个参数进行消费,但无需返回结果
。使用时需指定一个泛型来定义参数类型
@FunctionalInterface public interface Consumer<T> { /** * Performs this operation on the given argument. * @param t the input argument */ void accept(T t); }
-
使用:将输入的数据统一转换为小写输出
public class ConsumerTest { public static void main(String[] args) { test(msg -> { //编写消费逻辑 System.out.println(msg + "-> 转换为小写:" + msg.toLowerCase()); }); //Hello World-> 转换为小写:hello world } public static void test(Consumer<String> consumer){ //输入消费数据 consumer.accept("Hello World"); } }
-
默认default方法:
andThen(Consumer<? super T> after)
,先消费然后在消费
,先执行调用andThen接口的accept方法,然后在执行andThen方法参数after中的accept方法。default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; }
public class ConsumerAndThenTest { public static void main(String[] args) { test2(msg1 -> { System.out.println(msg1 + "-> 转换为小写:" + msg1.toLowerCase()); }, msg2 -> { System.out.println(msg2 + "-> 转换为大写:" + msg2.toUpperCase()); }); //Hello World-> 转换为大写:HELLO WORLD //Hello World-> 转换为小写:hello world } public static void test2(Consumer<String> c1, Consumer<String> c2) { String str = "Hello World"; //c1.accept(str); // 转小写 //c2.accept(str); // 转大写 //c1.andThen(c2).accept(str); c2.andThen(c1).accept(str); } }
-
练习:格式化打印信息
public class ConsumerAndThenTest2 { public static void main(String[] args) { String[] array = { "大雄,男", "静香,女", "胖虎,男"}; printInfo( s -> System.out.print("姓名:" + s.split(",")[0] + ","), //姓名不换行打印 s -> System.out.println("性别:" + s.split(",")[1] + "。"),//性别换行打印 array ); // 姓名:大雄,性别:男。 // 姓名:静香,性别:女。 // 姓名:胖虎,性别:男。 } private static void printInfo(Consumer<String> one, Consumer<String> two, String[] array) { for (String info : array) { one.andThen(two).accept(info); } } }
3.Function<T,R>
: 函数型接口
-
有参有返回值的接口,Function接口是
根据一个类型的数据得到另一个类型的数据
,前者称为前置条件
,后者称为后置条件
。- 抽象方法: R apply(T t),
传入一个参数,返回想要的结果。
@FunctionalInterface public interface Function<T, R> { /** * Applies this function to the given argument. * @param t the function argument * @return the function result */ R apply(T t); }
- 抽象方法: R apply(T t),
-
使用:传递进入一个字符串返回一个数字
public class FunctionTest { public static void main(String[] args) { test(msg -> { return Integer.parseInt(msg); }); //apply = 666 } public static void test(Function<String, Integer> function) { Integer apply = function.apply("666"); System.out.println("apply = " + apply); } }
-
默认方法:andThen,也是用来进行组合操作
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }
-
练习:数据处理
-
将字符串截取数字年龄部分,得到字符串;
-
将上一步的字符串转换成为int类型的数字;
-
将上一步的int数字累加100,得到结果int数字
public class FunctionAndThenTest { public static void main(String[] args) { String str = "赵丽颖,20"; int age = getAgeNum(str, //传入字符 s -> s.split(",")[1], //将字符串截取数字年龄部分,得到字符串 s2 -> Integer.parseInt(s2),//将上一步的字符串转换成为int类型的数字; s3 -> s3 += 100//将上一步的int数字累加100,得到结果int数字 ); System.out.println(age); //120 } private static int getAgeNum(String str, Function<String, String> one, Function<String, Integer> two, Function<Integer, Integer> three) { return one.andThen(two).andThen(three).apply(str); } }
-
-
默认的
compose方法
的作用顺序和andThen方法刚好相反- compose(Function<? super V, ? extends T> before),先执行compose方法参数before中的apply方法,然后将执行结果传递给调用compose函数中的apply方法在执行。
Function<Integer, Integer> function1 = e -> e * 2; Function<Integer, Integer> function2 = e -> e * e; Integer apply2 = function1.compose(function2).apply(3); System.out.println(apply2);
- compose(Function<? super V, ? extends T> before),先执行compose方法参数before中的apply方法,然后将执行结果传递给调用compose函数中的apply方法在执行。
-
而静态方法identity则是,输入什么参数就返回什么参数
4. Predicate<T>
: 断言型接口
-
抽象方法: boolean test(T t),传入一个参数,返回一个布尔值。
- 有参且返回值为Boolean的接口
@FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); }
public class PredicateTest { public static void main(String[] args) { test(msg -> { return msg.length() > 3; }, "HelloWorld"); //b:true } private static void test(Predicate<String> predicate, String msg) { boolean b = predicate.test(msg); System.out.println("b:" + b); } }
在Predicate中的默认方法提供了逻辑关系操作 and or negate isEquals
方法
- and(Predicate<? super T> other),相当于
逻辑&&
,当两个Predicate函数的返回结果都为true时才返回true。 - or(Predicate<? super T> other) ,相当于逻辑||,当两个Predicate函数的返回结果有一个为true则返回true,否则返回false。
- negate(),这个方法的意思就是取反。
public class PredicateDefaultTest {
public static void main(String[] args) {
test(msg1 -> {
return msg1.contains("H");
}, msg2 -> {
return msg2.contains("W");
});
//false
//true
//false
}
private static void test(Predicate<String> p1, Predicate<String> p2) {
/*boolean b1 = predicate.test(msg);
boolean b2 = predicate.test("Hello");*/
// b1 包含H b2 包含W
// p1 包含H 同时 p2 包含W
boolean bb1 = p1.and(p2).test("Hello");
// p1 包含H 或者 p2 包含W
boolean bb2 = p1.or(p2).test("Hello");
// p1 不包含H
boolean bb3 = p1.negate().test("Hello");
System.out.println(bb1); // FALSE
System.out.println(bb2); // TRUE
System.out.println(bb3); // FALSE
}
}
练习:数据筛选
- 必须为女生;
- 姓名为4个字
public class PredicateTest2 {
public static void main(String[] args) {
String[] array = {
"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女"};
List<String> list = filter(
array,
s -> "女".equals(s.split(",")[1]), //Predicate1 性别为女
s -> s.split(",")[0].length() == 4//Predicate2 姓名长度等于4
);
System.out.println(list);//[迪丽热巴,女, 古力娜扎,女]
}
private static List<String> filter(String[] array, Predicate<String> one, Predicate<String> two) {
List<String> list = new ArrayList<>();
for (String info : array) {
if (one.and(two).test(info)) {
list.add(info);
}
}
return list;
}
}
四.其他函数式接口
1.Bi类型接口: BiConsumer
BiConsumer、BiFunction、BiPrediate 是 Consumer、Function、Predicate
的扩展,可以传入多个参数
,没有 BiSupplier 是因为 Supplier 没有入参
以BiConsumer为例,这个接口跟 Consumer接》很像,都是消费的意思
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
/**本接口中的accept先执行,传入的BiConsumer 接口类型的参数,后执行accept*/
default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
Objects.requireNonNull(after);
return (l, r) -> {
accept(l, r);
after.accept(l, r);
};
}
}
- 该接口接收
2个泛型参数
,跟Consumer一样,都有一个accept方法
,只不过,这里的,接收两个泛型参数
,对这两个参数做下消费处理;
使用这个函数式接口的终端操作有map的遍历
Map<String, String> map = new HashMap<>();
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
map.put("d", "d");
map.forEach((k, v) -> {
System.out.println(k);
System.out.println(v);
});
- Map接口的终端操作,forEach的参数就是
BiConsumer函数接口
,对HashMap 的数据进行消费;BiConsumer函数接口还有一个默认函数,andThen
,接收一个BiConsumer接口,先执行本接口的,再执行传入的参数
。
2.UnaryOperator接口
- 只接收一个泛型参数T,继承Function接口,也就是说,传入泛型T类型的参数,调用apply后,返回也T类型的参数;
这个接口定义了一个静态方法,返回泛型对象的本身;
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
/**
* Returns a unary operator that always returns its input argument.
* @param <T> the type of the input and output of the operator
* @return a unary operator that always returns its input argument
*/
static <T> UnaryOperator<T> identity() {
return t -> t;
}
}
UnaryOperator<Integer> dda = x -> x + 1;
System.out.println(dda.apply(10));// 11
UnaryOperator<String> ddb = x -> x + 1;
System.out.println(ddb.apply("aa"));// aa1
五.操作基本数据类型的接口
IntConsumer、IntFunction、IntPredicate、IntSupplier、LongConsumer、LongFunction、LongPredicate、LongSupplier、DoubleConsumer、DoubleFunction、DoublePredicate、DoubleSupplier。 常用的函数式接口就那四大接口Consumer、Function、Prediate、Supplier
,其他的函数式接口可以去java.util.function
这个包下详细的看。