函数式接口在Java中是指:有且仅有一个抽象方法的接口。
使用注解:@FunctionalInterface
一般可以作为方法的参数和返回值类型。
一、基本使用:方法入参
MyFunctionalInterface:
package com.itheima.demo01.FunctionalInterface;
/*
函数式接口:有且只有一个抽象方法的接口,称之为函数式接口
当然接口中可以包含其他的方法(默认,静态,私有)
@FunctionalInterface注解
作用:可以检测接口是否是一个函数式接口
是:编译成功
否:编译失败(接口中没有抽象方法抽象方法的个数多余1个)
*/
@FunctionalInterface
public interface MyFunctionalInterface {
//定义一个抽象方法
public abstract void method();
}
MyFunctionalInterfaceImpl:
package com.itheima.demo01.FunctionalInterface;
public class MyFunctionalInterfaceImpl implements MyFunctionalInterface{
@Override
public void method() {
// do something
}
}
测试类:
package com.itheima.demo01.FunctionalInterface;
/*
函数式接口的使用:一般可以作为方法的参数和返回值类型
*/
public class Demo {
//定义一个方法,参数使用函数式接口MyFunctionalInterface
public static void show(MyFunctionalInterface myInter){
myInter.method();
}
public static void main(String[] args) {
//1-调用show方法,方法的参数是一个接口,所以可以传递接口的实现类对象
show(new MyFunctionalInterfaceImpl());
//2-调用show方法,方法的参数是一个接口,所以我们可以传递接口的匿名内部类
show(new MyFunctionalInterface() {
@Override
public void method() {
System.out.println("使用匿名内部类重写接口中的抽象方法");
}
});
//3-调用show方法,简化Lambda表达式
show(()-> System.out.println("使用Lambda表达式重写接口中的抽象方法"));
}
}
常用的Runnable示例:
public class Demo01Runnable {
public static void startThread(Runnable run){
new Thread(run).start();
}
public static void main(String[] args) {
//调用startThread方法,方法的参数是一个接口,那么我们可以传递这个接口的匿名内部类
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+"线程启动了");
}
});
//优化Lambda表达式
startThread(()->System.out.println(Thread.currentThread().getName()+"-->"+"线程启动了"));
}
}
二、基本使用:方法出参
Demo02Comparator:
public class Demo02Comparator {
public static Comparator getComparator(){
return new Comparator() {
@Override
public int compare(String o1, String o2) {
//按照字符串的降序排序
return o2.length()-o1.length();
}
};
//继续优化Lambda表达式
return (o1, o2)->o2.length()-o1.length();
}
public static void main(String[] args) {
String[] arr = {"aaa","b","cccccc","dddddddddddd"};
System.out.println(Arrays.toString(arr));//[aaa, b, cccccc, dddddddddddd]
Arrays.sort(arr,getComparator());
System.out.println(Arrays.toString(arr));//[dddddddddddd, cccccc, aaa, b]
}
}
三、常用案例
jdk8之后新增的一个重要的包 : java.util.function。
该包下所有的接口都是函数式接口, 按分类主要分为四大接口类型: Function、Consumer、Predicate、Supplier
3.1 Supplier
Demo01Supplier:
public class SupplierDemo {
public static List getNums(int num, Supplier sup){
List list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = sup.get();//核心在这里,将函数直接传入并使用
list.add(n);
}
return list;
}
public static void main(String[] args) {
List list = getNums(5, new Supplier() {
@Override
public Integer get() {
return (int)Math.random()*100;
}
});
//简写
List lt = getNums(5,()-> (int)Math.random()*100);
}
}
3.2Consumer
Demo01Consumer:
public class Demo01Consumer {
public static void method(String name, Consumer con){
con.accept(name);
}
public static void main(String[] args) {
method("赵丽颖", new Consumer() {
@Override
public void accept(String s) {
System.out.println(new StringBuffer(s).reverse().toString());
}
});
//简化
method("赵丽颖",(String name)->{
System.out.println(new StringBuffer(name).reverse().toString());
});
}
}
Demo02AndThen:
package com.itheima.demo05.Consumer;
import java.util.function.Consumer;
/*
Consumer接口的默认方法andThen
作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费
*/
public class Demo02AndThen {
public static void method(String s, Consumer con1 ,Consumer con2){
con1.andThen(con2).accept(s);//con1连接con2,先执行con1消费数据,在执行con2消费数据
}
public static void main(String[] args) {
method("Hello",
(t)->{
System.out.println(t.toUpperCase());
},
(t)->{
System.out.println(t.toLowerCase());
});
}
}
3.3Predicate
Demo01Predicate:
package com.itheima.demo06.Predicate;
import java.util.function.Predicate;
/*
java.util.function.Predicate接口
作用:对某种数据类型的数据进行判断,结果返回一个boolean值
Predicate接口中包含一个抽象方法:
boolean test(T t):用来对指定数据类型数据进行判断的方法
结果:
符合条件,返回true
不符合条件,返回false
*/
public class Demo01Predicate {
public static boolean checkString(String s, Predicate pre){
return pre.test(s);
}
public static void main(String[] args) {
String s = "abcdef";
boolean b = checkString(s,str->str.length()>5);
System.out.println(b);
}
}
Demo02Predicate_and:
package com.itheima.demo06.Predicate;
import java.util.function.Predicate;
/*
需求:判断一个字符串,有两个判断的条件
1.判断字符串的长度是否大于5
2.判断字符串中是否包含a
两个条件必须同时满足,我们就可以使用&&运算符连接两个条件
Predicate接口中有一个方法and,表示并且关系,也可以用于连接两个判断条件
default Predicate and(Predicate super T> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) && other.test(t);
}
方法内部的两个判断条件,也是使用&&运算符连接起来的
*/
public class Demo02Predicate_and {
public static boolean checkString(String s, Predicate pre1,Predicate pre2){
return pre1.and(pre2).test(s);//等价于return pre1.test(s) && pre2.test(s);
}
public static void main(String[] args) {
String s = "abcdef";
boolean b = checkString(s,(String str)->{
return str.length()>5;
},(String str)->{
return str.contains("a");
});
System.out.println(b);
}
}
Demo03Predicate_or:
package com.itheima.demo06.Predicate;
import java.util.function.Predicate;
/*
需求:判断一个字符串,有两个判断的条件
1.判断字符串的长度是否大于5
2.判断字符串中是否包含a
满足一个条件即可,我们就可以使用||运算符连接两个条件
Predicate接口中有一个方法or,表示或者关系,也可以用于连接两个判断条件
default Predicate or(Predicate super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
方法内部的两个判断条件,也是使用||运算符连接起来的
*/
public class Demo03Predicate_or {
public static boolean checkString(String s, Predicate pre1, Predicate pre2){
return pre1.or(pre2).test(s);//等价于return pre1.test(s) || pre2.test(s);
}
public static void main(String[] args) {
String s = "bc";
boolean b = checkString(s,(String str)->{
return str.length()>5;
},(String str)->{
return str.contains("a");
});
System.out.println(b);
}
}
demo04.Predicate_negate:
package com.itheima.demo06.Predicate;
import java.util.function.Predicate;
/*
需求:判断一个字符串长度是否大于5
如果字符串的长度大于5,那返回false
如果字符串的长度不大于5,那么返回true
所以我们可以使用取反符号!对判断的结果进行取反
Predicate接口中有一个方法negate,也表示取反的意思
default Predicate negate() {
return (t) -> !test(t);
}
*/
public class Demo04Predicate_negate {
public static boolean checkString(String s, Predicate pre){
return pre.negate().test(s);//等效于return !pre.test(s);
}
public static void main(String[] args) {
String s = "abc";
boolean b = checkString(s,(String str)->{
return str.length()>5;
});
System.out.println(b);
}
}
3.4 Function
Demo01Function
package com.itheima.demo07.Function;
import java.util.function.Function;
/*
java.util.function.Function接口用来根据一个类型的数据得到另一个类型的数据,
前者称为前置条件,后者称为后置条件。
Function接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。
使用的场景例如:将String类型转换为Integer类型。
*/
public class Demo01Function {
public static void change(String s, Function fun){
int in = fun.apply(s);//自动拆箱 Integer->int
System.out.println(in);
}
public static void main(String[] args) {
String s = "1234";
change(s,(String str)->{
return Integer.parseInt(str);
});
//优化Lambda
change(s,str->Integer.parseInt(str));
}
}
Demo02Function_andThen:
package com.itheima.demo07.Function;
import java.util.function.Function;
/*
Function接口中的默认方法andThen:用来进行组合操作
需求:把String类型的"123",转换为Inteter类型,把转换后的结果加10;把增加之后的Integer类型的数据,转换为String类型 */
public class Demo02Function_andThen {
public static void change(String s, Function fun1,Function fun2){
String ss = fun1.andThen(fun2).apply(s);
System.out.println(ss);
}
public static void main(String[] args) {
String s = "123";
change(s,(String str)->{
return Integer.parseInt(str)+10;
},(Integer i)->{
return i+"";
});
//优化Lambda表达式
change(s,str->Integer.parseInt(str)+10,i->i+"");
}
}