有且只有一个抽象方法的接口
被称为函数式接口,函数式接口适用于函数式编程
的场景,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);
}
}
Supplier
: 供给型接口抽象方法: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);
}
}
Consumer
:消费型接口抽象方法: 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);
}
}
}
Function
: 函数型接口有参有返回值的接口,Function接口是根据一个类型的数据得到另一个类型的数据
,前者称为前置条件
,后者称为后置条件
。
传入一个参数,返回想要的结果。
@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);
}
使用:传递进入一个字符串返回一个数字
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方法刚好相反
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);
而静态方法identity则是,输入什么参数就返回什么参数
Predicate
: 断言型接口抽象方法: boolean test(T t),传入一个参数,返回一个布尔值。
@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
方法
逻辑&&
,当两个Predicate函数的返回结果都为true时才返回true。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
}
}
练习:数据筛选
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;
}
}
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);
});
BiConsumer函数接口
,对HashMap 的数据进行消费;BiConsumer函数接口还有一个默认函数,andThen
,接收一个BiConsumer接口,先执行本接口的,再执行传入的参数
。@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
/**
* Returns a unary operator that always returns its input argument.
* @param 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
这个包下详细的看。