🍍 函数式接口引入
函数式接口是只含有一个抽象方法的接口。但是可以含有多个非抽象方法。
package function; @FunctionalInterface public interface Demo { void print(); // void insert();//不可以含有多个抽象方法 static void method() { } public static int age()//静态方法 { return 1; } default void make()//default修饰的普通方法 { System.out.println("....."); } }
在使用函数式接口的时候,非常适用的是我们可以用lambda去创建接口的对象。很方便判断一个接口是不是一个函数式接口的办法就是在接口上方添加注解@FunctionalInterface进行检测。
这其实就是一种函数式编程,体现了一种逻辑思维。函数式编程的一个非常方便的体现就是lambda表达式。所以函数式接口非常适合配合lambda去使用。
而要配合lambda表达式去使用,就需要要求接口中只有一个抽象方法。否则是无法满足lambda的使用语法规定的。
🍍 自定义函数式接口
我们可以自己定义函数式接口,上面的概述已经说过了。还是比较简单的,其实在文lambda表达式中所举的一些例子中也体现了函数式接口的特点。
简单演示一下使用
先定义一个接口
package function; @FunctionalInterface public interface Demo { void print(); // void insert(); static void method() { } public static int age()//静态方法 { return 1; } default void make()//default修饰的普通方法 { System.out.println("....."); } }
然后定义一个测试类
package function; public class Demo_Use { public static void main(String[] args) { useDemo(()-> System.out.println("函数式接口的使用")); } private static void useDemo(Demo p) { p.print(); p.make(); Demo.age(); Demo.method();//静态方法为类所有,我们可以这样去调用。 } }
🍍 java中常见的几种函数式接口
🍌 Predicate函数式接口
Interface Predicate
这是一个功能界面,因此可以用作lambda表达式或方法引用的赋值对象。
方法说明
and(Predicate<? super T> other)
返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND。
isEqual(Object targetRef)
返回根据 Objects.equals(Object, Object)测试两个参数是否相等的 谓词
negate()
返回表示此谓词的逻辑否定的谓词。
or(Predicate<? super T> other)
返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑或
test(T t)
在给定的参数上评估这个谓词。
可以看的出可以进行一些逻辑操作。我们可以去简单使用几个方法感受一些这种编程思维。
package function; import java.util.ArrayList; import java.util.function.Predicate; public class PredicateTest { 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[] strArry, Predicate<String> pre1, Predicate<String> pre2) { //定义一个集合 ArrayList<String> array = new ArrayList<>(); //遍历数组 for(String str: strArry) { if (pre1.and(pre2).test(str))//我们对str进行一个操作,然后满足的就是两个限制条件。 { array.add(str); } } return array; } }
package function; import java.util.function.Predicate; public class PredicateDemo01 { public static void main(String[] args) { checkString("Hello",(String s)->{ boolean b = s.length() > 8; return b; }); //优化 boolean b1 = checkString("Hello",s->s.length()>8); System.out.println(b1); } private static boolean checkString(String s, Predicate<String> pre) { // return pre.test(s); //进行逻辑非的操作 return pre.negate().test(s); } //判断给定的字符串是否满足要求 }
package function; import java.util.function.Predicate; public class PredicateDemo02 { public static void main(String[] args) { boolean b1 = checkString("hello",s->s.length()>8); System.out.println(b1); boolean b2 = checkString("helloworld",s->s.length()>8); boolean b3 = checkString("hello",s->s.length()>8,s->s.length()<15); System.out.println(b3); } //同一个字符串给出不同的条件,最后把这两个判断的结果做逻辑与运算的结果作为返回 private static boolean checkString(String s,Predicate<String>pre,Predicate<String>pre1) { boolean test = pre.test(s); boolean test2 = pre1.test(s); boolean b = test && test2; return b; } private static boolean checkString(String s, Predicate<String> pre) { return pre.test(s); } }
这种编程思维还是很有趣的,是java8推出的函数式编程。相关的方法,只要一看代码就明白了。
🍌 Supplier函数式接口
Interface Supplier
这是一个功能界面,因此可以用作lambda表达式或方法引用的赋值对象。
@FunctionalInterface
public interface Supplier代表结果供应商。
没有要求每次调用供应商时都会返回新的或不同的结果。
这是一个functional interface的功能方法是get() 。
这个函数式接口非常简单,提供的唯一一个方法就是get()
直接举例使用
package function; import java.util.function.Supplier; public class SupplierTest { public static void main(String[] args) { //定义一个int数组 int[] arr = {16,13,14,35}; int max1 = getMax(() -> { int max = arr[0]; for (int i = 0; i < arr.length; i++) { if (arr[i] > max) { max = arr[i]; } } return max; }); System.out.println(max1); } private static int getMax(Supplier<Integer>sup) { return sup.get(); } }
package function; import java.util.function.Supplier; public class SupplierDemo { public static void main(String[] args) { // String s = getString(()->{ // return "jgdabc"; // }); String s = getString(() -> "jgdabc"); 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(); } }
🍌Consumer函数式接口
Interface Consumer
表示接受单个输入参数并且不返回结果的操作。 与大多数其他功能界面不同, Consumer预计将通过副作用进行操作。
我们通常也可以把这个接口函数称作消费类型接口
主要提供了两个方法
accept(T t)
对给定的参数执行此操作。
andThen(Consumer<? super T> after)
返回一个组合的 Consumer ,按顺序执行该操作,然后执行 after操作。
package function; import java.util.function.Consumer; public class ConsumerDemo { public static void main(String[] args) { // operatorString("jgdabc",(String s)->{ // System.out.println(s);//消费的动作 // }); //优化 operatorString("jgdabc",s-> System.out.println(s)); //方法引用 operatorString("jgdabc",System.out::println); //反转 operatorString("jgdabc",s ->{ String s1 = new StringBuilder(s).reverse().toString(); System.out.println(s1); } ); //优化 operatorString("jgdabc",s-> System.out.println(new StringBuilder(s).reverse().toString())); operator("jgdabc",s-> System.out.println(new StringBuilder(s).reverse().toString()),s-> System.out.println(s)); } //定义一个方法,对一个字符串数据进行两次消费 private static void operator(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);//传入字符串 } }
package function; import java.util.function.Consumer; public class ConsumerTest { public static void main(String[] args) { String[] strArray = {"jgdabc,16", "nsaasj,23", "sjansak,15"}; printInfo(strArray, (String str) -> { String name = str.split(",")[0]; System.out.println("姓名" + name); }, (String str) -> { int age = Integer.parseInt(str.split(",")[1]); System.out.println(",年龄:" + age); }); //优化 printInfo(strArray,str-> System.out.println("姓名"+str.split(",")[0]),str-> System.out.println("年龄"+Integer.parseInt(str.split(",")[1]))); } private static void printInfo(String[] strArray, Consumer<String> con1, Consumer<String> con2) { for (String str : strArray) { con1.andThen(con2).accept(str); } } }
🍌Function函数式接口
public interface Function<T,R>
表示接受一个参数并产生结果的函数。
注意它的泛型和说明,我们可以认为接收T类型的参数,然后返回R类型的结果。表达的就是这个意思。
然后我们去使用它,先看一下提供的方法。
andThen(Function<? super R,? extends V> after)
返回一个组合函数,首先将该函数应用于其输入,然后将 after函数应用于结果。
apply(T t)
将此函数应用于给定的参数。
compose(Function<? super V,? extends T> before)
返回一个组合函数,首先将 before函数应用于其输入,然后将此函数应用于结果。
identity()
返回一个总是返回其输入参数的函数。
代码举例
package function; import java.util.function.Function; public class FunctionTest { public static void main(String[] args) { String s = "林青霞,30"; convert(s, (String ss) -> { return ss.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) { Integer i = fun1.andThen(fun2).andThen(fun3).apply(s); System.out.println(i); } }
package function; import java.util.function.Function; public class FunctionDemo { public static void main(String[] args) { convert("100",(String s)->{ return Integer.parseInt(s); }); //优化 convert("100",Integer::parseInt); convert(100,i->String.valueOf(i+100)); convert("100",s->Integer.parseInt(s),i->String.valueOf(i+66)); } //定义一个方法,把一个字符串转换为int类型,加上一个整数,然后转换为字符串,在控制台输出 private static void convert(String s,Function<String,Integer>fun1,Function<Integer,String> fun2) { Integer i = fun1.apply(s); String s1 = fun2.apply(i); System.out.println(s1); //改进 String ss = fun1.andThen(fun2).apply(s); System.out.println(ss); } //定义一个方法,把一个int类型的数据加上一个整数之后,然后转换为字符串在控制台输 private static void convert(int i,Function<Integer,String>fun) { String s = fun.apply(i); System.out.println(s); } //定义一个方法,将字符串转换为int类型,并在控制台输出 private static void convert(String s, Function<String,Integer>fun) { Integer i = fun.apply(s); } }
这些函数接口函数都是十分简单的,提供的方法接收实际的处理逻辑还是在lambda中有主要的体现。当然也可以在调用的函数定义中进行提前的逻辑处理。注意泛型等返回特点就好了。