函数式接口
概念
函数式接口是指:有且只有一个抽象方法的接口。
函数式接口,即适用于函数式编程场景的接口,而Java中的函数式编程体现的就是Lambad,所以函数式接口就是适用于Lambda适用的接口,只要确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利进行推导。
函数式接口格式
修饰符 interface 接口名称{
public abstract 返回值类型 方法名称(参数信息);
}
public interface MyFunctionInterace{
public abstract void method();
}
@FunctionalInterface 注解
Java8 中专门为 函数式接口引入了一个全新的注解:@FunctionalInterface,该注解用于在一个接口的定义上
@FunctionalInterface
public interface MyFunctionInterace{
public abstract void method();
}
一旦适用该注解来标记接口,编译器会强制检查该接口是否有且只有一个抽象方法,否则就会编译报错
常用的函数式接口
Supplier:生产者
java.util.function.Supplier<T> 接口被称为生产型接口,指定接口中的泛型是什么类型,那么接口中的 抽象方法就会生产什么类型
抽象方法:get
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
使用:求数组中的最大值
public class Demo02Test {
public static void main(String[] args) {
int[] arr = {100, 0, -50, 88, 99, 33, -30};
//调用getMax方法,方法的参数Supplier是一个函数式接口,所以可以 传递Lambda表达式
int arrMax = getMax(() -> {
//获取数组的最大值,并返回
//定义一个变量,把数组中的第一个元素赋值给该变量,记录数组中的最大值
int max = arr[0];
for (int i : arr) {
//使用其他元素和最大值比较
if (max < i)
//如果i 大于max ,则替换max作为最大值
max = i;
}
return max;
});
System.out.println(arrMax);
}
//定义一个方法,用于获取int类型数组中的最大值,方法的参数传递Supplier接口,泛型使用Integer
public static int getMax(Supplier<Integer> sup) {
return sup.get();
}
}
Consumer:消费者
java.util.function.Consumer<T>
接口则正好与Supplier接口相反,它不是生成一个数据,而是消费一个数据,其数据类型由泛型决定
抽象方法:accept
Consumer 接着中包含的抽象方法 accept ,意为消费一个指定执行泛型的数据
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
//基本使用
public class Demo09Consumer {
private static void consumeString(Consumer<String> function) {
function.accept("Hello");
}
public static void main(String[] args) {
consumeString(s -> System.out.println(s));
}
}
默认方法:andThen
如果一个方法的参数和返回值都是 Consumer 类型,那么就可以实现效果:消费数据的时候,首先做一个操作,然后再做一个操作,实现组合。那那么就可以使用默认方法 andThen
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
提示:java.util.Objects
的requireNonNull
静态方法将会在参数为null时主动抛出NullPointerException
异常。
使用:先输出字符串的大写,再输出字符串的小写
public class Demo10ConsumerAndThen {
private static void consumeString(Consumer<String> one, Consumer<String> two) {
//con1.adnThen(con2); 谁写前边谁先消费
one.andThen(two).accept("Hello");
}
public static void main(String[] args) {
consumeString(
s -> System.out.println(s.toUpperCase()),
s -> System.out.println(s.toLowerCase()));
}
}
//这样写看起来很高大上,但是感觉很鸡肋,其实完全可以写在一起,先大写再小写
Predicate:判断者
需要对某种类型的数据进行判断,得到一个boolean值结果。这时可以使用java.util.function.Predicate<T>
接口
抽象方法:test
Predicate
接口中包含一个抽象方法:boolean test(T t)
。用于条件判断的场景:
public class DemoPredicate {
/*
boolean test(T t):用来对指定数据类型数据进行判断的方法
定义一个方法 对字符串长度进行判断,大于5返回true
*/
public static boolean checkString(String s, Predicate<String> p) {
return p.test(s);
}
public static void main(String[] args) {
//定义一个字符串
String s = "abcdef";
boolean b = checkString(s, ele -> ele.length() > 5);
System.out.println(b);
}
}
默认方法:and
既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个Predicate
条件使用“与”逻辑连接起来实现“并且”的效果时,可以使用default方法and
。其JDK源码为:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
如果要判断一个字符串的长度既要大于5,又要包含小写“a”:
public class DemoPreicate_and {
public static void main(String[] args) {
String str = "abcde";
boolean a = checkString(str, ele -> ele.length() > 5, ele -> ele.contains("a"));
System.out.println(a);
}
public static boolean checkString(String s, Predicate<String> p1, Predicate<String> p2) {
return p1.and(p2).test(s);
}
}
默认方法:or
与and
的“与”类似,默认方法or
实现逻辑关系中的“或”。JDK源码为:
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
如果要判断一个字符串的长度大于5或者包含小写“a”
public class DemoPredicate_or {
public static void main(String[] args) {
String str = "bcdef1";
boolean b = checkString(str, ele -> ele.length() > 5, ele -> ele.contains("a"));
System.out.println(b);
}
public static boolean checkString(String s, Predicate<String> p1, Predicate<String> p2) {
return p1.or(p2).test(s);
}
}
默认方法:negate
negate方法就是对boolean值进行取反,真为假,假为真 ,其JDK源码为:
default Predicate<T> negate() {
return (t) -> !test(t);
}
使用:
/**
* 判断一个字符串的长度是否大于5
* 如果字符串的长度大于5,那么返回false
* 如果字符串的长度不大于5,那么返回true
*/
public class DemoPredicate_negate {
public static void main(String[] args) {
String str = "abc";
boolean b = checkString(str, ele -> ele.length() > 5);
System.out.println(b);
}
public static boolean checkString(String s, Predicate<String> p1) {
return p1.negate().test(s);
}
}
Function:转换者
java.util.function.Function<T,R>
接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。
抽象方法:apply
Function
接口中最主要的抽象方法为:R apply(T t)
,根据类型T的参数获取类型R的结果。
使用的场景例如:将String
类型转换为Integer
类型。
public class Demo01Function {
public static void change(String s, Function<String, Integer> fun) {
int in = fun.apply(s); //自动拆箱
System.out.println(in);
}
public static void main(String[] args) {
String s = "1234";
change(s, ele -> Integer.parseInt(ele));
}
}
如果需要了解Lambda的使用,请查看我的另一篇博客:Java8新特性 :Lambda表达式一