函数式接口
函数式接口是指有且只有一个抽象方法,但是可以有多个非抽象方法的接口
格式:
修饰符 interface 接口名称{
public abstract 返回值类型 (参数列表);
//其他非抽象方法的内容
}
@FunctionalInterface注解
与 @Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解: @FunctionalInterface 。该注 解可用于一个接口的定义上:
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}
一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。需要注 意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。
函数式接口可以作为方法的参数和返回值
public class Demo09FunctionalInterface {
// 使用自定义的函数式接口作为方法参数
private static void doSomething(MyFunctionalInterface inter) {
inter.myMethod(); // 调用自定义的函数式接口方法
}
public static void main(String[] args) {
// 调用使用函数式接口的方法
doSomething(() ‐> System.out.println("Lambda执行啦!"));
}
}
Lambda表达式的性能优化
Lambda的特点:延迟加载
Lambda的使用前提,必须存在函数式接口
定义一个函数式接口
@FunctionalInterface
public interface MessageBuilder{
//定义一个抽象方法来返回字符串的信息
public abstract String builderMessage();
}
使用Lambda优化日志案例
public class Demo02Lambda {
//定义一个显示日志的方法,方法的参数传递日志的等级和
// MessageBuilder接口
public static void showLog(int level, MessageBuilder mb){
//对日志的等级进行判断,如果是1级,则调用MessageBuilder接口中的builderMessage方法
if(level==1){
System.out.println(mb.builderMessage());
}
}
public static void main(String[] args) {
//定义三个日志信息
String msg1 = "Hello";
String msg2 = "World";
String msg3 = "Java";
/*
使用Lambda表达式作为参数传递,仅仅是把参数传递到showLog方法中
只有满足条件,日志的等级是1级
才会调用接口MessageBuilder中的方法builderMessage
才会进行字符串的拼接
如果条件不满足,日志的等级不是1级
那么MessageBuilder接口中的方法builderMessage也不会执行
所以拼接字符串的代码也不会执行
所以不会存在性能的浪费
*/
showLog(1,()->{
System.out.println("不满足条件不执行");
//返回一个拼接好的字符串
return msg1+msg2+msg3;
});
}
}
常用的函数式接口
Supplier接口
java.util.function.Supplier接口仅包含一个无参的方法:T get()。
用来获取一个泛型参数指定类型的对象数据。
Supplier接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据
public class Demo01Supplier {
//定义一个方法,方法的参数传递Supplier<T>接口,泛型执行String,get方法就会返回一个String
public static String getSupplier(Supplier<String> sup){
return sup.get();
}
public static void main(String[] args) {
//调用getSupplier方法,因为参数是Supplier接口,所以可以使用Lambda表达式
String s1=getSupplier(()->{
return "小明";
});
//优化Lambda表达式
String s2 = getSupplier(() -> "小美");
System.out.println(s1+s2);
}
}
Consumer接口
java.util.function.Consumer接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定。
Consumer接口中包含抽象方法
- void accept(T t),意为消费一个指定泛型的数据。
Consumer接口是一个消费型接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据
至于具体怎么消费(使用),需要自定义(输出,计算…)
public class Demo01Consumer {
/*
定义一个方法
方法的参数传递一个字符串的姓名
方法的参数传递Consumer接口,泛型使用String
可以使用Consumer接口消费字符串的姓名
*/
public static void method(String name, Consumer<String> con){
con.accept(name);
}
public static void main(String[] args) {
//调用method方法,传递字符串姓名,方法的另一个参数是Consumer接口,是一个函数式接口,所以可以传递Lambda表达式
method("赵丽颖",(String name)->{
//对传递的字符串进行消费
//消费方式:直接输出字符串
//System.out.println(name);
//消费方式:把字符串进行反转输出
String reName = new StringBuffer(name).reverse().toString();
System.out.println(reName);
});
}
}
知识点:
- Consumer接口中泛型用的什么数据类型,其中的accept方法就消费什么数据类型,具体怎么消费要看具体的情况,以上代码数据类型是字符串,使用消费方式是直接输出
- 因为方法参数传递的是Consumer函数式接口,所以可以使用Lambda表达式
- StringBuffer类线程安全,可变的字符序列。 字符串缓冲区就像一个String ,但可以修改。 在任何时间点,它包含一些特定的字符序列,但可以通过某些方法调用来更改序列的长度和内容。
字符串缓冲区可以安全地被多个线程使用。
构造方法
-StringBuffer(String str) 构造一个初始化为指定字符串内容的字符串缓冲区。
成员方法
-StringBuffer reverse() 导致该字符序列被序列的相反代替。
-String toString() 返回表示此顺序中的数据的字符串。
Consumer接口的默认方法andThen
作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费
例如:
Consumer con1
Consumer con2
String s = “hello”;
con1.accept(s);
con2.accept(s);
连接两个Consumer接口 再进行消费
con1.andThen(con2).accept(s); 谁写前边谁先消费
Predicate接口
java.util.function.Predicate接口
作用:对某种数据类型的数据进行判断,结果返回一个boolean值
Predicate接口中包含一个抽象方法:
- boolean test(T t):用来对指定数据类型数据进行判断的方法
结果:
符合条件,返回true
不符合条件,返回false
方法and()、or()和negate()
逻辑表达式:可以连接多个判断的条件
&&:与运算符,有false则false
||:或运算符,有true则true
!:非(取反)运算符,非真则假,非假则真
需求:判断一个字符串,有两个判断的条件
1.判断字符串的长度是否大于5
2.判断字符串中是否包含a
两个条件必须同时满足,我们就可以使用&&运算符连接两个条件
Predicate接口中有一个方法and,表示并且关系,也可以用于连接两个判断条件
源码
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) && other.test(t);
}
方法内部的两个判断条件,也是使用&&运算符连接起来的
Predicate接口中有一个方法or,表示或者关系,也可以用于连接两个判断条件
源码
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
方法内部的两个判断条件,也是使用||运算符连接起来的
Predicate接口中有一个方法negate,也表示取反的意思
default Predicate<T> negate() {
return (t) -> !test(t);
}
Function<T,R>接口
java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据,
前者称为前置条件,后者称为后置条件。
Function接口中最主要的抽象方法为:
- R apply(T t),根据类型T的参数获取类型R的结果。
使用的场景例如:将String类型转换为Integer类型。
Function接口中的默认方法 - andThen:用来进行组合操作