一、函数式接口的概念
在java中有且仅有一个抽象的方法的接口称为函数式接口(可以包含默认、静态、私有的方法)
lambda表达式其实就是函数式接口的体现,lambda表达式中的->其实就是指的一个函数式接口箭头后面的方法体就是函数式接口中那个抽象方法。(因为函数式接口中只有一个抽象方法,所以lambda表达式所指向的方法只有那一个)
/**
* 定义一个函数式接口并调用其方法
*/
public class Demo1 {
public static void main(String[] args) {
Demo1 demo1 = new Demo1();
demo1.show(()-> System.out.println("使用lambda表达式重写接口中的抽象方法"));
}
public void show(MyFunctionInterface myFunctionInterface){
myFunctionInterface.method();
}
}
@FunctionalInterface
interface MyFunctionInterface{
void method();
}
二、函数式编程
lambda表达式的延迟执行特性性能优化
性能浪费案例
/**
* 通过lambda表达式来优化日志,避免性能浪费
*/
public class OptimizationLog {
public static void main(String[] args) {
String msg1 = "Hello" ;
String msg2 = "Word" ;
String msg3 = "!!!!!" ;
OptimizationLog demo = new OptimizationLog();
// demo.toShow(1,msg1+msg2+msg3);
/**
* 使用lambda表达式,传递参数调用方法,只有满足条件才会调用作为参数的函数式接口
* 如果日志等级不为1 那么就不会调用后面的函数式接口,也就不会进行字符串拼接,不存在性能浪费
*/
// demo.toShow1(1,()->msg1+msg2+msg3);
demo.toShow1(2,()->{
System.out.println("不满足条件不执行");
return msg1+msg2+msg3;
});
}
/**
* 如果日志等级为1则输出拼接后的字符串
* @param level
* @param msg
*/
public void toShow(int level ,String msg){
if (1==level){
System.out.println(msg);
}
/**
* 这种方式无论日志等级是是否为1字符串都会拼接,造成性能的浪费
*/
}
/**
* 通过函数式接口
* @param level
* @param messageBuilder
*/
public void toShow1(int level ,MessageBuilder messageBuilder){
if (1==level){
System.out.println(messageBuilder.buider());
}
}
}
@FunctionalInterface
interface MessageBuilder{
String buider();
}
情景:
当日志等级为1的时候,将消息拼接返回。如果用传统的方法进行参数的传递,在toShow方法中无论这个日志等级是否为1后面的msg都会拼接。这样就造成了性能的浪费。
通过lambda表达式的延迟执行特性来对这个日志案例进行优化:
将日志等级和一个函数式接口作为入参写了一个toShow1方法
通过lambda表达式来调用这个方法
demo.toShow1(2,()->{
System.out.println("不满足条件不执行");
return msg1+msg2+msg3;
});
此时日志等级为2,并不满足方法中日志为1的条件,所以不会后面调用函数式接口中的方法。所以也不会进行字符串拼接的操作,避免了性能的浪费。
只有满足条件才会调用函数式接口中的方法。
lambda表达式作为参数传递,仅仅是把参数传递到方法中
常用的函数式接口
1、Supplier函数式接口
Supplier是一个生产型的函数式接口,T为出参,无入参。该接口只有一个方法get(),用于获取指定泛型类型对象。
2、Consumer函数式接口
Consumer是一个消费型的函数式接口,有入参无出参,因为没有出参所以多用于打印之类的消费型操作,其中有两个方法
1).accept()对给定的参数做操作
2).andThen是Consumer接口的一个默认方法,用于决定两个函数式接口作为入参的先后执行顺序。下面是该方法的源码
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
/**
* 练习1:将Consumer作为入参动作来对对象进行消费
* {"张三,男","李四,女"} --->> 姓名:张三 性别:男 。。。。。。
*/
public class ConsumerDemo2 {
public static void userInfo(String[] users, Consumer<String> consumer1, Consumer<String> consumer2){
for (String user:
users) {
consumer1.andThen(consumer2).accept(user);
}
}
public static void main(String[] args) {
String[] users = {"张三,男","李四,女"};
userInfo(users,(userInfo)->{
String name = userInfo.split(",")[0];
System.out.print("姓名:" + name);
},(userInfo)->{
String sex = userInfo.split(",")[1];
System.out.println(" " + "性别:" + sex);
});
}
}
3、Predicate函数式接口
该接口中的三个方法(and,or,negate)相当于逻辑运算的与或非。通过两个方法来进行逻辑判断来返回一个Boolean类型的值
/**
* 练习:要求将名字为四个字的女生输出
*/
public class PredicateDemo {
public static void main(String[] args) {
// Predicate<String> predicate1 = o -> o.equals("123");
// Predicate<String> predicate2 = o -> o.length()>1;
// System.out.println(predicate1.or(predicate2).test("123"));
String[] peoples = {"迪丽热巴,女","古力娜扎,女","张翰,男","赵丽颖,女"};
ArrayList<String> list = demo1(peoples,
people -> people.split(",")[0].length() == 4,
people -> people.split(",")[1].equals("女")
);
list.forEach(System.out::println);
}
public static ArrayList<String> demo1(String[] arrays, Predicate<String> predicate1, Predicate<String> predicate2){
ArrayList<String> list = new ArrayList<>();
for (String array:
arrays) {
Boolean b = predicate1.and(predicate2).test(array);
if (b){
list.add(array);
}
}
return list;
}
}
4、Function函数式接口
Function<T, R>通过参数T来指定传入参数的类型,后置的R是指定返回数据的类型。通常用于类型的转换,该方法中的andThen与Consumer的andThen方法是一样的。compose方法与andThen上的逻辑恰好是相反的。我感觉就是Supplier和Consumer两个接口的结合体。规定入参和出参的类型。
/**
*通过Function函数式接口,将"赵丽颖,20"中的20截取出来转换为integer后加100
*/
public class FunctionDemo2 {
public static void main(String[] args) {
String people = "赵丽颖,20";
Integer ageAndAdd = getAgeAndAdd(people, info -> Integer.parseInt(info.split(",")[1]), age -> age + 100);
System.out.println(ageAndAdd);
}
public static Integer getAgeAndAdd(String peoples, Function<String,Integer> function1, Function<Integer,Integer> function2){
return function1.andThen(function2).apply(peoples);
}
}