版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cszhang570221322/article/details/84656329
在java8中
1、新推出了一个接口概念:函数式接口。
2、允许接口也可以有default方法,default方法可以方法体。
他满足以下规范:
- 接口有且只能有个一个抽象方法(抽象方法只有方法定义,没有方法体)
- 不能在接口中覆写Object类中的public方法(写了编译器也会报错)
- 允许有default实现方法。
如下例子是函数式接口:
package zzu.zwl.main;
/**
* Created by zwl on 2018/11/30.
* May god bless me
*/
@FunctionalInterface
public interface GreetingService {
String sayMessage(String message);
default void doSomeMoreWork1()
{
// Method body
}
default void doSomeMoreWork2()
{
// Method body
}
static void printHello(){
System.out.println("Hello");
}
@Override
String toString(); //Object中的方法,但不重写
}
而@FunctionalInterface是干什么的?
当你添加上这个注解后,仅仅是检查是否符合函数式接口规范,而不具有其他作用,因此jdk8之前常用的匿名内部类监听器类也可以使用lambda编程,如下
//ActionListener的Java源码如下,他没有使用@FunctionalInterface注解
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package java.awt.event;
import java.util.EventListener;
/**
* The listener interface for receiving action events.
* The class that is interested in processing an action event
* implements this interface, and the object created with that
* class is registered with a component, using the component's
* {@code addActionListener} method. When the action event
* occurs, that object's {@code actionPerformed} method is
* invoked.
*
* @see ActionEvent
* @see <a href="http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html">How to Write an Action Listener</a>
*
* @author Carl Quinn
* @since 1.1
*/
public interface ActionListener extends EventListener {
/**
* Invoked when an action occurs.
* 只有一个未定义方法,符合函数式接口规范。
* @param e the event to be processed
*/
public void actionPerformed(ActionEvent e);
}
/**
*下面是例子
*
**/
package zzu.zwl.main;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Created by zwl on 2018/11/30.
* May god bless me
*/
public class Main {
private static JButton jButton;
public static void main(String[] args) {
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.paramString());
}
});
//也可以用lambda表达式编程,只关注输入和输出,虽然很 actionPerformed的输出为void类型。
jButton.addActionListener(e -> System.out.println(e.paramString()));
}
}
明白了以上代码,接下来是函数式编程与匿名内部类的对比编程。
package zzu.zwl.main;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Created by zwl on 2018/11/30.
* May god bless me
*/
public class Main {
private static JButton jButton;
public static void main(String[] args) {
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.paramString());
}
});
jButton.addActionListener(e -> System.out.println(e.paramString()));
/**
* 为了更好理解FunctionInterface,暂且抛开lambda不看
* 这里不过是传统的两个步骤
* 1、定义了一个方法,两个参数,传入一个字符串,调用接口的方法
*
* 这里相当于,先调用joinStr方法,传入'你好'和一个匿名内部类(匿名内部类实现了getMessage方法)
* 代码执行顺序为先进入joinStr方法,然后执行方法体
* 方法体是调用接口的sayMessage方法(传入的是这里的str '你好'),
* 因此代码执行顺序为
* jdk8之前---1
* jdk8之前---2
* jdk8之前---3
* jdk8之前---4
* jdk8之前---5
*/
String msg= joinStr("你好", new GreetingService() { // jdk8之前---1
@Override
public String sayMessage(String message) { //实现接口的方法。
System.out.println("匿名接口"); // jdk8之前---3
return message; // jdk8之前---4
}
});
/**
* 打印
*/
System.out.println(msg); // jdk8之前---7
/**
* 1.接收一个message,执行一部分动作,然后如果FunctionInterface有返回值,则返回一个对应的返回值。
* 这里用jdk8以前理解方式是 定义一个匿名内部类,相当于如下形式,所以代码不会执行
GreetingService greetingService = new GreetingService() {
@Override
public String sayMessage(String message) {
System.out.println(message);
return message + "i";
}
};
*
*/
GreetingService greetingService1 = message -> {
System.out.println(message);
return message + "i";
};
/**
* 2.本质上与1相似,但是此处是方法引用 ,相当于JDK8之前的如下形式
* GreetingService greetingService2 = new GreetingService() {
@Override
public String sayMessage(String message) {
return Main.getInstance(message);
}
};
*
*/
GreetingService greetingService2 = Main::getInstance;
/**
* 这里传来传去,实际上就是"你好"-->getInstance:item了,只不过中间规范化的定义一个接口,不同的是以前用匿名内部类实现,
* 现在不关注类,而只关注抽象方法,接口相当于约束了传入参数和返回参数,从而使用lambda表达式来书写,只关注计算过程的输入和输出,有一点点函数编程的思想。
*/
String msg1= joinStr("你好",greetingService2);
System.out.println(msg1);
//3与上述过程2一致。
GreetingService greetingService2_1 = message -> Main.getInstance(message);
//4与上述过程2、3一致。
GreetingService greetingService2_2 = message -> {
return Main.getInstance(message);
};
String msg1_1 = joinStr("你好",greetingService2_1);
System.out.println(msg1_1);
String msg1_2 = joinStr("你好",greetingService2_2);
System.out.println(msg1_2);
System.out.println("****************************华丽分割线**********************");
/**
* 上面看着是不是很鸡肋,下面的例子实践后会很方便。
*/
//这样是不是简便很多,不用定义这个匿名内部类,直接关注输入(传入参数),输出(返回值)
String msg3 = joinStr("这个值传给旁边的message:",message -> message+"Hello,World");
//实现具体方法的时候用多行代码。 为了复习,下面的代码再用JDK8之前的重写一遍。
String msg4 = joinStr("这个值传给旁边的message",message -> {
System.out.println("你好呀,函数式编程。");
return message+"Hello,World";
});
String BeforeJdk8_msg4=joinStr("这个值传给旁边的message:", new GreetingService() {
@Override
public String sayMessage(String message) {
System.out.println("你好呀,函数式编程。");
return message+"Hello,World";
}
});
System.out.println(msg3);
System.out.println(msg4);
System.out.println(BeforeJdk8_msg4);
}
/**
* 简单方法
* @param item
* @return
*/
public static String getInstance(String item) {
return item + "!世界";
}
/**
* 简单方法
* @param massage
* @return
*/
public static String getMessage(String massage){
return "世界,"+ massage+"!";
}
/**
* 定义一个方法,两个参数
* @param str 字符串类型
* @param greetingService 一个传接口,调用接口里的一个方法sayMessage,很常见的方法参数类型
* @return
*/
public static String joinStr(String str,GreetingService greetingService) {
String s = greetingService.sayMessage(str); // jdk8之前--2(进入sayMessage方法) jdk8之前--5(sayMessage方法返回)
return s; //jdk8之前---6 joinStr方法返回返回值
}
}