函数式接口
函数式接口:有且仅有一个抽象方法的接口
格式:(只要确保接口中有且仅有一个抽象方法即可)
修饰符 interface 接口名称{
public abstract 返回值类型 方法名称(可选参数信息)
// 其他非抽象方法内容
}
由于接口当中抽象方法的public abstract 是可以省略的:
public interface MyFunctionalInterface {
void myMethod();
}
@FunctionalInterface注解
@FunctionalInterface,该注解可用于一个接口的定义上:
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}
ps:一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错
自定义函数式接口
public class Demo09FunctionalInterface {
// 使用自定义的函数式接口作为方法参数
private static void doSomething(MyFunctionalInterface inter) {
inter.myMethod(); // 调用自定义的函数式接口方法
}
public static void main(String[] args) {
// 调用使用函数式接口的方法
doSomething(() ‐> System.out.println("Lambda执行啦!"));
}
}
常用函数接口
Supplier接口
java.util.function.Supplier 接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对
象数据。由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
package LambdaInterfaceDemo;
import java.util.function.Supplier;
public class Demo01Supplier {
public static void main(String[] args) {
String s=getString(()->{
return "胡歌";
});
System.out.println(s);
}
public static String getString(Supplier<String> sup){
return sup.get();
}
}
package LambdaInterfaceDemo;
/*练习:求数组元素最大值
使用Supplier接口作为方法参数类型,通过Lambda表达式求出int数组中最大值
提示:接口泛型请使用Java.lang.Interger
*/
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
public class Demo02Suplier {
//定义一个方法,用于获取int类型数组中元素的最大值,方法参数传递Supplier接口,泛型使用Integer
public static int getMax(Supplier<Integer> sup){
return sup.get();
}
public static void main(String[] args) {
int[] arr ={10,2,4,-19,44};
final int[] max = {arr[0]};
//调用getMax方法,方法的参数Supplier是一个函数式接口,所以可以传递Lambda表达式
int result = getMax(()->{
//比遍历数组,获取数组其他元素
for (int i:arr){
if (i> max[0]){
max[0] =i;
}
}
//返回最大值
return max[0];
});
System.out.println(result);
}
}
Consumer接口
java.util.function.Consumer 接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定。
抽象方法:accept
package LambdaInterfaceDemo;
import java.util.function.Consumer;
/*
Consumer接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据
定义一个方法
方法的参数传递一个字符串姓名
方法的参数传递Consumer接口,泛型使用String
可以使用Consumer接口消费字符串的姓名
*/
public class Demo02Consumer {
public static void main(String[] args) {
method1("赵丽颖",(String name)->{
//System.out.println(name);
String reName = new StringBuffer(name).reverse().toString();
System.out.println(reName);
});
}
public static void method1(String name,Consumer<String> con){
con.accept(name);
}
}
默认方法:andThen
package LambdaInterfaceDemo;
import java.util.function.Consumer;
/*Comsumer 默认方法andThen
作用:把两个Consumer接口组合到一起对数据进行消费
Consumer<String> con1
Consumer<String> con2
String s ="hello;
con1.accept(s);
con.2accept(s);
连接两个consumer接口在进行消费
con1.andThen(con).accept(s)
*/
public class Demo02AndThen {
public static void main(String[] args) {
method("Hello", (String s)->{
System.out.println(s.toLowerCase());
}, (String s)->{
System.out.println(s.toUpperCase());
});
}
public static void method(String s, Consumer<String> con1,Consumer<String> con2){
//con1.accept(s);
//con2.accept(s);
con1.andThen(con2).accept(s);
}
}
练习:格式化打印信息
package LambdaInterfaceDemo;
/*练习:字符串数组中存有多条信息,请按照格式“姓名:XX。性别:XX。”的格式将信息打印出来
要求将打印姓名的动作作为第一个Consumer接口的Lambda实例
将打印性别的动作作为打印Consumer接口的Lambda实例
将两个Consumeer接口按顺序拼接在一起
*/
import java.util.function.Consumer;
public class Demo02Practice {
public static void main(String[] args) {
//定义一个字符串型数组
String[] str = {"迪丽热巴,女","古力娜扎,女","马儿扎哈,男"};
//调用method方法,传递一个字符串数组和两个Lambda表达式
/* method(str,(message)->{
String name = message.split(",")[0];
System.out.println(name);
},(message)->{
String sex =message.split(",")[1];
System.out.println(sex);
});*/
}
public static void method(Consumer<String> con1,Consumer<String> con2,String[] s){
for (String message:s){
con1.andThen(con2).accept(message);
}
}
}
Predicate接口
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用java.util.function.Predicate 接口。
抽象方法:test
Predicate 接口中包含一个抽象方法: boolean test(T t) 。用于条件判断的场景:
package LambdaInterfaceDemo;
import java.util.function.Predicate;
/*
Predicate<T>接口作用:
对某种数据类型的数据进行判断,结果返回一个Boolean值
Predicate方法中包含一个抽象方法
boolean test(T t)//用来对指定数据类型进行判断的方法
*/
public class Demo02Predict {
public static void main(String[] args) {
String str= "ASCdfs";
boolean boo =checkMethod(str,s->{
return s.length()>8;
});
System.out.println(boo);
}
public static boolean checkMethod(String s, Predicate<String> pre){
return pre.test(s);
}
}
默认方法:and
既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个Predicate 条件使用“与”逻辑连接起来实现“并且”的效果时,可以使用default方法and
package LambdaInterfaceDemo;
/*逻辑表达式:可以连接多个判断的条件
&&:与运算符,有false则为false
||:或运算符,有true则为true
!:非(取反)运算符,非真则假,非假则真*/
import java.util.function.Predicate;
public class Demo02Predict_and {
public static void main(String[] args) {
String str="qwe123";
boolean boo =checkString(str,s -> {
return s.length()<4;
},s -> {
return s.length()>7;
});
System.out.println(boo);
}
public static boolean checkString(String s, Predicate<String>pre1,Predicate<String>pre2){
return pre1.and(pre2).test(s);
}
}
默认方法:or
与and 的“与”类似,默认方法or 实现逻辑关系中的“或”。
默认方法:negate
“与”、“或”已经了解了,剩下的非”(取反)也会简单。默认方法negate
Function接口
java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。
抽象方法:apply
Function 接口中最主要的抽象方法为: R apply(T t) ,根据类型T的参数获取类型R的结果。使用的场景例如:将String 类型转换为Integer 类型。
package LambdaInterfaceDemo;
import java.util.function.Function;
public class Demo02Function_apply {
/*定义一个方法
方法的参数传递一个字符串类型的整数
方法的参数传递一个Function接口,泛型使用<String,Integer>
使用Function接口中的apply,把字符串类型的整数,转换成Integer类型的整数
*/
public static void main(String[] args) {
//定义一个字符串类型整数
/* String str="567";
change(str,(String,s)->{
return Integer.parseInt(s);
});
*/
}
public static void change(String s, Function<String,Integer> fun){
int in=fun.apply(s);
System.out.println(in);
}
}
默认方法:andThen
Function 接口中有一个默认的andThen 方法,用来进行组合操作
package LambdaInterfaceDemo;
import java.util.function.Function;
public class Demo02Function_andThen {
public static void main(String[] args) {
String str ="123";
change(str,(String s)->{
return Integer.parseInt(s)+10;},
(Integer i)->{
return i+"";
});
}
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);
}
}
练习:自定义函数模型拼接
package LambdaInterfaceDemo;
/*练习:自定义函数拼接(使用Function)
String str = "赵丽颖,20";
分析:
1、截取字符串得到年龄部分的字符串
Function<String String> "赵丽颖,20"->"20"
2、将上一步的字符串转换int类型的数字
Function<String,Integer>"20"->20
3、将上一步的int数字累加100,得到结果int数字
Function<Integer,Integer>20->120
*/
import java.util.function.Function;
public class Demo02FunctionPractice {
/* 定义一个方法
参数传递包含姓名和年龄的字符串
参数再传递3个Function接口用于类型转换*/
public static void main(String[] args) {
String ss = "赵丽颖,20";
int num = method(ss, (String s) -> {
return s.split(",")[1];
}, (String s) -> {
return Integer.parseInt(s);
},
(Integer i) -> {
return i + 100;
});
System.out.println(num);
}
public static int method(String s, Function<String,String> fun1,Function<String,Integer>fun2,Function<Integer,Integer> fun3){
return fun1.andThen(fun2).andThen(fun3).apply(s);
}
}