1、有且只有一个抽象方法的接口
2、函数式接口,即适用于函数式编程场景的接口。
Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。
只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。
public interface InterfaceName { public abstract 返回值类型 方法名称(可选参数信息); // 其他非抽象方法内容 } public interface MyFunctionalInterface { void myMethod(); }
@FunctionalInterface public interface MyFunctionalInterface { void myMethod(); }
一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。
需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。
Supplier
、 Consumer
、 Predicate
、 Function
@FunctionalInterface public interface Supplier<T> { T get(); }
/** * Supplier 供给型接口 没有参数,只有返回值 */ public class Demo04 { public static void main(String[] args) { // Supplier supplier = new Supplier<Integer>() { // @Override // public Integer get() { // System.out.println("get()"); // return 1024; // } // }; Supplier supplier = ()->{ return 1024; }; System.out.println(supplier.get()); } }
/** * 常用的函数式接口 * java.util.function.Supplier<T>接口仅包含一个无参的方法:T get()。 * 用来获取一个泛型参数指定类型的对象数据。 * * Supplier<T>接口被称之为生产型接口,指定接口的泛型是什么类型 * 那么接口中的get方法就会生产什么类型的数据 */ public class SupplierDemo01 { //定义一个方法,方法的参数传递Supplier<T>接口,泛型执行String,get方法就会返回一个String public static String getString(Supplier<String> sup){ return sup.get(); } public static void main(String[] args) { String string = getString(() -> { return "胡歌"; }); System.out.println(string); //优化Lambda表达式 String s2 = getString(()->"胡歌"); System.out.println(s2); } } /** * 练习:求数组元素最大值 * 使用Supplier接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值。 * 提示:接口的泛型请使用java.lang.Integer类。 */ public class TestDemo02 { public static int getMax(Supplier<Integer> supplier){ return supplier.get(); } public static void main(String[] args) { //定义一个int类型的数组,并赋值 int[] arr = {100,0,-50,880,99,33,-30}; //调用getMax方法,方法的参数Supplier是一个函数式接口,所以可以传递Lambda表达式 int maxValue = getMax(()->{ //获取数组的最大值,并返回 //定义一个变量,把数组中的第一个元素赋值给该变量,记录数组中元素的最大值 int max = arr[0]; //遍历数组,获取数组中的其他元素 for (int i : arr) { //使用其他的元素和最大值比较 if (i>max) max = i; //如果i大于max,则替换max作为最大值 } return max; }); System.out.println(maxValue); } }
消费性接口
@FunctionalInterface // 只有输入,没有返回值 public interface Consumer<T> { void accept(T t); default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
/** * Consumer 消费型接口: 只有输入,没有返回值 */ public class Demo03 { public static void main(String[] args) { // Consumer<String> consumer = new Consumer<String>() { // @Override // public void accept(String str) { // System.out.println(str); // } // }; Consumer<String> consumer = (str)->{System.out.println(str);}; consumer.accept("sdadasd"); } }
消费一个指定泛型的数据
/** * java.util.function.Consumer<T>接口则正好与Supplier接口相反, * 它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定。 * Consumer接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据。 * * Consumer接口是一个消费型接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据 * 至于具体怎么消费(使用),需要自定义(输出,计算....) */ public class ConsumerDemo01 { public static void method(String name, Consumer<String> consumer){ consumer.accept(name); } public static void main(String[] args) { //Consumer<String> consumer = (str)->{System.out.println(str);}; //consumer.accept("sdadasd"); //accept中的name值"赵丽颖"赋值给了下面的name method("赵丽颖",(String name)->{ //对传递的字符串进行消费 //消费方式:直接输出字符串 System.out.println(name); //消费方式:把字符串进行反转输出 String reName = new StringBuffer(name).reverse().toString(); System.out.println(reName); }); } }
"一步接一步”操作
/** * Consumer接口的默认方法andThen * 作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费 * * 例如: * Consumer<String> con1 * Consumer<String> con2 * String s = "hello"; * con1.accept(s); * con2.accept(s); * 连接两个Consumer接口 再进行消费 * con1.andThen(con2).accept(s); 谁写前边谁先消费 */ public class ConsumerAndThenDemo02 { //定义一个方法,方法的参数传递一个字符串和两个Consumer接口,Consumer接口的泛型使用字符串 public static void method(String s, Consumer<String> con1,Consumer<String> con2){ //con1.accept(s); //con2.accept(s); //使用andThen方法,把两个Consumer接口连接到一起,在消费数据 //con1连接con2,先执行con1消费数据,在执行con2消费数据 con1.andThen(con2).accept(s); } public static void main(String[] args) { method("Hello",(t)->{ System.out.println(t.toUpperCase()); },(t)->{ System.out.println(t.toLowerCase()); }); } }
断言型接口:有一个输入参数,返回值只能是布尔值
@FunctionalInterface public interface Predicate<T> { boolean test(T t); default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } default Predicate<T> negate() { return (t) -> !test(t); } default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
/** * 断定型接口:有一个输入参数,返回值只能是 布尔值! */ public class Demo02 { public static void main(String[] args) { //判断字符串是否为空 // Predicate<String> predicate = new Predicate<String>(){ // @Override // public boolean test(String str) { // return str.isEmpty(); // } // }; Predicate<String> predicate = (str)->{return str.isEmpty(); }; System.out.println(predicate.test("")); } }
用于条件判断的场景
/** * java.util.function.Predicate<T>接口 * 作用:对某种数据类型的数据进行判断,结果返回一个boolean值 * * Predicate接口中包含一个抽象方法: * boolean test(T t):用来对指定数据类型数据进行判断的方法 * 结果: * 符合条件,返回true * 不符合条件,返回false */ public class PredicateDemo01 { /* 定义一个方法 参数传递一个String类型的字符串 传递一个Predicate接口,泛型使用String 使用Predicate中的方法test对字符串进行判断,并把判断的结果返回 */ public static boolean checkString(String s, Predicate<String> pre){ return pre.test(s); } public static void main(String[] args) { //定义一个字符串 String s = "abcdef"; //调用checkString方法对字符串进行校验,参数传递字符串和Lambda表达式 /*boolean b = checkString(s,(String str)->{ //对参数传递的字符串进行判断,判断字符串的长度是否大于5,并把判断的结果返回 return str.length()>5; });*/ //优化Lambda表达式 boolean b = checkString(s,str->str.length()>5); System.out.println(b); } }
逻辑并。两个条件同时满足返回true
/** * 需求:判断一个字符串,有两个判断的条件 * 1.判断字符串的长度是否大于5 * 2.判断字符串中是否包含a * 两个条件必须同时满足,我们就可以使用&&运算符连接两个条件 */ public class PredicateAndDemo02 { public static boolean checkString(String s, Predicate<String> pre1,Predicate<String> pre2){ //等价于return pre1.test(s) && pre2.test(s); return pre1.and(pre2).test(s); } public static void main(String[] args) { //定义一个字符串 String s = "abcdef"; //调用checkString方法,参数传递字符串和两个Lambda表达式 boolean b = checkString(s,(String str)->{ //判断字符串的长度是否大于5 return str.length()>5; },(String str)->{ //判断字符串中是否包含a return str.contains("a"); }); System.out.println(b); } }
逻辑或,两个条件满足一个返回true
/** * 需求:判断一个字符串,有两个判断的条件 * 1.判断字符串的长度是否大于5 * 2.判断字符串中是否包含a * 满足一个条件即可,我们就可以使用||运算符连接两个条件 * */ public class PredicateOrDemo03 { /* 定义一个方法,方法的参数,传递一个字符串 传递两个Predicate接口 一个用于判断字符串的长度是否大于5 一个用于判断字符串中是否包含a 满足一个条件即可 */ public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){ //return pre1.test(s) || pre2.test(s); return pre1.or(pre2).test(s);//等价于return pre1.test(s) || pre2.test(s); } public static void main(String[] args) { //定义一个字符串 String s = "bc"; //调用checkString方法,参数传递字符串和两个Lambda表达式 boolean b = checkString(s,(String str)->{ //判断字符串的长度是否大于5 return str.length()>5; },(String str)->{ //判断字符串中是否包含a return str.contains("b"); }); System.out.println(b); } }
结果取反
/** * 需求:判断一个字符串长度是否大于5 * 如果字符串的长度大于5,那返回false * 如果字符串的长度不大于5,那么返回true * 所以我们可以使用取反符号!对判断的结果进行取反 */ public class PredicateNegateDemo04 { /** * 定义一个方法,方法的参数,传递一个字符串 * 使用Predicate接口判断字符串的长度是否大于5 */ public static boolean checkString(String s, Predicate<String> pre){ //return !pre.test(s); return pre.negate().test(s);//等效于return !pre.test(s); } public static void main(String[] args) { //定义一个字符串 String s = "abc"; //调用checkString方法,参数传递字符串和Lambda表达式 boolean b = checkString(s,(String str)->{ //判断字符串的长度是否大于5,并返回结果 return str.length()>5; }); System.out.println(b); } }
@FunctionalInterface // T 传入参数、R返回类型 public interface Function<T, R> { R apply(T t); default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } 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 函数型接口, 有一个输入参数,有一个输出 * 只要是 函数型接口 可以 用 lambda表达式简化 */ public class Demo01 { public static void main(String[] args) { // Function<String,String> function = new Function<String,String>() { // @Override // public String apply(String str) { // return str; // } // }; Function<String,String> function = (str)->{return str;}; System.out.println(function.apply("asd")); } }
/** * java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据, * 前者称为前置条件,后者称为后置条件。 * Function接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。 * 使用的场景例如:将String类型转换为Integer类型。 */ public class FunctionDemo01 { /** * 定义一个方法 * 方法的参数传递一个字符串类型的整数 * 方法的参数传递一个Function接口,泛型使用<String,Integer> * 使用Function接口中的方法apply,把字符串类型的整数,转换为Integer类型的整数 */ public static void change(String s, Function<String,Integer> fun){ //Integer in = fun.apply(s); int in = fun.apply(s);//自动拆箱 Integer->int System.out.println(in); } public static void main(String[] args) { //定义一个字符串类型的整数 String s = "1234"; //调用change方法,传递字符串类型的整数,和Lambda表达式 change(s,(String str)->{ //把字符串类型的整数,转换为Integer类型的整数返回 return Integer.parseInt(str); }); //优化Lambda change(s,str->Integer.parseInt(str)); } }
组合操作
/** * Function接口中的默认方法andThen:用来进行组合操作 * * 需求: * 把String类型的"123",转换为Inteter类型,把转换后的结果加10 * 把增加之后的Integer类型的数据,转换为String类型 * * 分析: * 转换了两次 * 第一次是把String类型转换为了Integer类型 * 所以我们可以使用Function<String,Integer> fun1 * Integer i = fun1.apply("123")+10; * 第二次是把Integer类型转换为String类型 * 所以我们可以使用Function<Integer,String> fun2 * String s = fun2.apply(i); * 我们可以使用andThen方法,把两次转换组合在一起使用 * String s = fun1.andThen(fun2).apply("123"); * fun1先调用apply方法,把字符串转换为Integer * fun2再调用apply方法,把Integer转换为字符串 */ public class FunctionAndThenDemo02 { /** * 定义一个方法 * 参数串一个字符串类型的整数 * 参数再传递两个Function接口 * 一个泛型使用Function<String,Integer> * 一个泛型使用Function<Integer,String> */ public static void change(String s, Function<String,Integer> fun1, Function<Integer,String> fun2){ String ss = fun1.andThen(fun2).apply(s); System.out.println(ss); } public static void main(String[] args) { //定义一个字符串类型的整数 String s = "123"; //调用change方法,传递字符串和两个Lambda表达式 change(s,(String str)->{ //把字符串转换为整数+10 return Integer.parseInt(str)+10; },(Integer i)->{ //把整数转换为字符串 return i+""; }); //优化Lambda表达式 change(s,str->Integer.parseInt(str)+10,i->i+""); } }