函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。
@FunctionalInterface注解
该注解可以用来检测该接口是否为函数式接口,将该注解放在 接口定义的上方,如果接口是函数式接口,编译通过;如果不是,编译失败
需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。
函数式接口的使用
作为方法的参数进行使用
/*
* 函数式接口作为方法的参数进行使用
*/
public class Test {
//定义一个方法threadStart,参数使用函数式接口Runnable
public static void threadStart(Runnable runnable){
new Thread(runnable).start();
}
public static void main(String[] args) {
//调用threadStart方法,方法的参数是一个接口,可以传递这个接口的匿名内部类
threadStart(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开启线程");
}
});
//使用Lambda表达式优化
threadStart(()->System.out.println(Thread.currentThread().getName()+"开启线程"));
}
}
作为返回值进行使用
/*
* 函数式接口作为返回值进行使用
*/
public class Test {
//定义一个方法,返回值类型为使用函数式接口Comparator
public static Comparator<String> getComparator(){
/*方法的返回值类型是一个接口,那么我们可以返回这个接口的匿名内部类
return new Comparator<String>() {
@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={"aa", "a", "aaa"};
Arrays.sort(arr,getComparator());
for (String s : arr) {
System.out.println(s);
}
}
}
常用函数式接口
Supplier接口
java.util.function.Supplier <T>
接口仅包含一个无参的方法:T get()
,用来获取一个泛型参数指定类型的对象数据
该接口被称为生产型接口,指定接口的泛型是什么类型,那么get方法就会产生什么类型的数据
抽象方法get
package com.hs_vae.FunctionalInterface;
import java.util.function.Supplier;
/*
java.util.function.Supplier<T> 接口仅包含一个无参的方法: T get(),用来获取一个泛型参数指定类型的对象数据
Supplier<T> 接口被称为生产型接口,指定接口的泛型是什么类型,那么get方法就会产生什么类型的数据
*/
public class Demo04SupplierGet {
//定义一个方法,方法的参数传递Supplier<T>接口,泛型执行String,get方法就返回一个String
public static String getString(Supplier<String> sup){
return sup.get();
}
public static void main(String[] args) {
//调用getString方法,参数是一个函数式接口可以使用Lambda表达式
String s = getString(() -> "hs-vae");
System.out.println(s);
}
}
Consumer接口介绍
java.util.function.Consumer<T>
接口与Supplier接口相反,被称之为消费型接口,它不是生产一个数据,而是消费一个数据,其数据类型由指定的泛型决定
该接口包含抽象方法void accept(T t)
,作用是消费一个指定泛型的数据,消费是自定义的(输出、计算….)
抽象方法accept
package com.hs_vae.FunctionalInterface;
import java.util.function.Consumer;
/*
java.util.function.Consumer<T> 接口与Supplier接口相反,被称之为消费型接口,它不是生产一个数据,而是消费一个数据,其数据类型由指定的泛型决定
该接口包含抽象方法void accept(T t),作用是消费一个指定泛型的数据,消费是自定义的(输出,计算....)
*/
public class Demo05ConsumerAccept {
//定义一个方法,方法的参数传递一个姓名和泛型为String的Consumer接口,可以使用该接口消费姓名
public static void show(String name, Consumer<String> cs){
cs.accept(name);
}
public static void main(String[] args) {
//调用show方法,参数里面包含函数式接口Consumer可以使用Lambda表达式
//消费方式:输出姓名
show("许嵩", System.out::println);
//消费方式:反转姓名并输出
show("许嵩",(String name)->{
String s = new StringBuffer(name).reverse().toString();
System.out.println(s);
});
}
}
//输出结果
许嵩
嵩许
默认方法andThen
该方法需要两个Consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费
package com.hs_vae.FunctionalInterface;
import java.util.function.Consumer;
/*
andThen方法需要两个Consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费
例如:
Consumer<String> con1
Consumer<String> con2
String s = "hs-vae";
连接两个Consumer接口,再进行消费
con1.andThen(con2).accept(s); 谁先写在前边谁先消费
*/
public class Demo06ConsumerAndThen {
//定义一个方法,方法的参数传递一个字符串和两个Consumer接口
public static void show(String s, Consumer<String> con1,Consumer<String> con2){
//使用andThen方法,把con1和con2两个接口连接到一起,再消费数据(先执行con1再执行con2)
con1.andThen(con2).accept(s);
}
public static void main(String[] args) {
//调用show方法,传递一个字符串,可以使用两个Lambda表达式
show("Hello",
(t)->{
//消费方式:把字符串转换为大写输出
System.out.println(t.toUpperCase());
},
(t)->{
//消费方式:把字符串转换为小写输出
System.out.println(t.toLowerCase());
});
}
}
//输出结果
HELLO
hello
Predicate接口介绍
当我们需要对某种类型的数据进行判断,从而得到一个boolean值结果,这时可以使用java.util.function.Predicate<T>
接口
抽象方法test
boolean test(T t):用来对指定数据类型数据进行判断的方法
符合条件,返回true
不符合条件,返回false
package com.hs_vae.FunctionalInterface;
import java.util.function.Predicate;
/*
java.util.function.Predicate<T> 接口
作用:对某种数据类型的数据进行判断,结果返回一个boolean值
Predicate接口中包含一个抽象方法:
- boolean test(T t):用来对指定数据类型数据进行判断的方法
符合条件,返回true
不符合条件,返回false
*/
public class Demo07PredicateTest {
//定义一个方法,参数传递一个字符串和Predicate接口,使用接口中的test方法进行判断,并返回结果
public static boolean checkString(String s, Predicate<String> p){
return p.test(s);
}
public static void main(String[] args) {
//定义一个字符串
String s = "hs-vae";
//调用checkString方法对字符串进行校验,参数中包含Predicate接口可以使用Lambda表达式
//校验规则为该字符串的长度是否大于5
boolean b = checkString(s, (t) -> t.length() > 4);
System.out.println(b); //true
}
}
默认方法and
给出一个案例
需求为:判断一个字符串,有两个判断的条件,第一判断字符串的长度是否大于5,第二字符串是否包含’a’ ,两个条件必须同时满足返回true
按照往常可以使用逻辑运算符&&连接两个条件
不过Predicate接口中有一个默认方法and,表示并且关系,也可以用于连接两个判断条件
该方法内部的两个判断条件就是使用逻辑运算符&&连接起来的
使用如下
package com.hs_vae.FunctionalInterface;
import java.util.function.Predicate;
/*
案例需求:
判断一个字符串,有两个判断的条件,条件一判断字符串的长度是否大于5,条件二字符串是否包含'a' ,两个条件必须同时满足时返回true
可以使用Predicate接口中的默认方法and
该方法的源码就是两个判断条件通过逻辑运算符&&(且)连接的
*/
public class Demo08PredicateAnd {
//定义一个方法,方法的参数传递一个字符串和两个Predicate接口(用于判断两个条件,必须同时成立)
public static boolean checkString(String s, Predicate<String> p1,Predicate<String> p2){
return p1.and(p2).test(s); //等同于return p1.test(s)&& p2.test(s)
}
public static void main(String[] args) {
//调用checkString方法,参数传递两个Predicate接口,可以使用两个Lambda表达式
//一个判断字符串长度是否大于5,另一个判断字符串是否包含'a',仅当同时满足时为返回true
boolean b = checkString("hs-vae", (t) -> t.length() > 5, (t) -> t.contains("a"));
System.out.println(b); //true
}
}
默认方法or
给出一个案例
需求为:判断一个字符串,有两个判断的条件,第一判断字符串的长度是否大于5,第二字符串是否包含’a’ ,当满足一个条件时返回true
按照往常可以使用逻辑运算符||连接两个条件
不过Predicate接口中有一个默认方法or,表示或关系,也可以用于连接两个判断条件
or方法内部的两个判断条件就是使用逻辑运算||符连接起来的
使用如下
package com.hs_vae.FunctionalInterface;
import java.util.function.Predicate;
/*
案例需求:
判断一个字符串,有两个判断的条件,条件一判断字符串的长度是否大于5,条件二字符串是否包含'a' ,一个条件成立时返回true
可以使用Predicate接口中的默认方法or
该方法的源码就是两个判断条件通过逻辑运算符||(或)连接的
*/
public class Demo09PredicateOr {
//定义一个方法,方法的参数传递一个字符串和两个Predicate接口(用于判断两个条件,一个条件成立即可)
public static boolean checkString(String s, Predicate<String> p1, Predicate<String> p2){
return p1.or(p2).test(s); //等同于return p1.test(s)|| p2.test(s)
}
public static void main(String[] args) {
//调用checkString方法,参数传递两个Predicate接口,可以使用两个Lambda表达式
//一个判断字符串长度是否大于5,另一个判断字符串是否包含'a',仅当同时满足时为返回true
boolean b = checkString("vae", (t) -> t.length() > 5, (t) -> t.contains("a"));
System.out.println(b); //true
}
}
默认方法negate
给出一个案例
需求为:判断一个字符串的长度是否大于5,如果字符串长度大于5返回false,反之返回true
可以使用取反符号!对判断的结果进行取反
也可以使用Predicate接口中的默认方法negate,也表示取反的意思
使用如下
package com.hs_vae.FunctionalInterface;
import java.util.function.Predicate;
/*
案例需求: 判断一个字符串的长度是否大于5
如果字符串长度大于5返回false,反之返回true
可以使用取反符号!对判断的结果进行取反
Predicate接口中的默认方法negate,也表示取反的意思
default Predicate<T> negate(){
return (t) -> !test(t);
}
*/
public class Demo10PredicateNegate {
//定义一个方法,参数传递一个字符串和一个Predicate接口(判断字符串长度是否大于5)
public static boolean checkString(String s , Predicate<String> p){
return p.negate().test(s); //等同于return !p.test(s);
}
public static void main(String[] args) {
//调用checkString方法,参数传递了一个Predicate接口,可以使用Lambda表达式
boolean b = checkString("vae", (t) -> t.length() > 5);
System.out.println(b); //true
}
}
Function接口介绍
java.util.function.Function<T,R>
接口为一个转换类型的接口,用来根据一个类型的数据得到另一个类型的数据,T称为前置条件,
R称为后置条件
抽象方法apply
Function接口中抽象方法为:R apply (T t)
,根据类型T的参数获取类型R的结果
给出案例
需求:将String类型转换为Integer类型
实现如下
package com.hs_vae.FunctionalInterface;
import java.util.function.Function;
public class Demo11FunctionApply {
/*
定义一个方法,参数传递一个字符串类型的整数和一个Function接口
使用Function接口中的方法apply,把字符串类型的整数转换为Integer类型的整数
*/
public static void change(String s, Function<String,Integer> f){
Integer i = f.apply(s);
System.out.println(i);
}
public static void main(String[] args) {
//调用change方法,传递字符串类型的整数,和Lambda表达式
change("123456",(s)->Integer.parseInt(s));
}
}
默认方法andThen
Function接口中的默认方法andThen,用来进行组合操作
给出案例
需求:把String类型的”123456″,转换为Integer类型并且加10,再转换为String类型
实现如下
package com.hs_vae.FunctionalInterface;
import java.util.function.Function;
/*
案例需求:把String类型的"123456",转换为Integer类型并且加10,再转换为String类型
*/
public class Demo12FunctionAndThen {
/*
定义一个方法,参数传递一个字符串类型的整数和两个Function接口
一个接口泛型为<String,Integer>
另一个接口泛型为<Integer,String>
*/
public static void change(String s, Function<String,Integer> f1,Function<Integer,String> f2){
String result = f1.andThen(f2).apply(s);
System.out.println(result);
}
public static void main(String[] args) {
//调用change方法,传递一个字符串类型的整数和两个Lambda表达式
change("10",s -> Integer.parseInt(s)+10,i -> i+"");
}
}