1.接口定义增强
- 在jdk1.7以及以前,接口内的方法只能写抽象方法,到了jdk1.8之后接口可以通过default以及static关键字编写带有方法体的方法了代码如下`
interface IMessage{
public void print();
default void fun() {
System.out.println("我可以定义普通方法了!");
}
public static void method() {
System.out.println("我可以定义静态方法了!");
}
}
以上代码颠覆了我们对接口的认知,但是可以解决当一个接口有很多子类的时候,新添加一个方法,并且这个方法又是相同代码的问题。
2.Lamda表达式
- 在之前我们再写匿名内部类的时候要写很多无用的代码例如:
public class Test{
/**在这里的参数我们用上面“1”中定义的接口*/
public static void fun(IMessage message){
message.print();
}
public static void main(String[] args){
fun(new IMessage() {
@Override
public void print() {
System.out.println("Hello World!");
}});
}
}
}
观察上面的代码我们会觉得这个匿名内部类的方法以及结构堆积在这看着很不爽,而Lamda表达式就能很好的解决这个问题
修改代码如下:
public static void main(String[] args){
fun(() -> System.out.println("Hello World!"));
}
使用Lamda表达式只需要一行就能搞定,但是这一行是什么意思呢?
首先我们调用的这个类的方法是没有参数的,并且只写一行代码,所以"()“就代表没有参数,后面加一个”->"然后再加一行语句,就完成了匿名内部类的所有操作。
Lamda表达式还支持多行的语句,例如:
public static void main(String[] args){
fun(() -> {
String str = "Hello World".toUpperCase();
System.out.println(str)}
);
}
这样就完成了多行语句的编写
3.方法引用
在jdk8中一共定义了四种方法引用
- 引用静态方法:
类名称 :: static方法名称
- 引用某个对象的方法:
实例化对象 :: 普通方法
- 引用特定类型方法:
特定类 :: 普通方法
- 引用构造方法:
类名称 :: new
- 说明引用静态方法:
/**
* 实现静态方法的引用接口
* @param <P> 表示引用方法的参数类型
* @param <R> 表示引用方法的返回值类型
*/
interface IFun<P,R> {
public R fun(P p);
}
public class Test{
public static void main(String[] args){
//引用了String类的静态方法valueOf()
IFun<Integer,String> fun = String :: valueOf;
String temp = fun.fun(1000);
System.out.println(temp.replace("0","9"));
}
}
- 举例说明引用普通方法:
/**
* 实现普通方法的引用接口
* @param <R> 表示引用方法的返回值类型
*/
interface IFun<R> {
public R upper();
}
public class Test{
public static void main(String[] args){
//引用了String对象的toUpperCase()方法
IFun<String> fun = "hello world":: toUpperCase;
String temp = fun.upper(1000);
System.out.println(temp);
}
}
通过以上两个代码我们发现,如果要实现引用函数,那么一定要用到接口,并且接口内必须只能定义一个方法,所以我们在定义接口的时候要加一个注解:“
@FunctionalInterface
”,在接口上方加上这个注解之后就表示,此接口为函数式接口,只能定义一个方法
- 引用特定类型方法,经过前面两个引用方法我们可以得知,类名加两个冒号再加方法名是引用静态方法的方式,而引用普通类的方式是实例化对象加两个冒号,但是有些情况比较特殊,有的方法是需要两个对象的,例如String类中有一个compareTo的方法,是需要比较两个对象是否相同,所以在引用这种特殊方法时如下所示:
/**
* 实现静态方法的引用接口
* @param <P> 表示引用方法的参数类型
*/
interface IFun<P> {
public int compare(P p1,P p2);
}
public class Test{
public static void main(String[] args){
//引用了String类的compareTo()方法
IFun<String> fun = String :: compareTo;
int temp = fun.compare("A","B");
System.out.println(temp);
}
}
- 引用构造方法
/**
* 实现静态方法的引用接口
* @param <R> 表示引用方法的参数类型
*/
interface IFun<R> {
public R create(String t,double p);
}
class Book{
private String title;
private double price;
public Book(String title,double price){
this.title = title;
this.price = price;
}
public String toString(){
return "书名为:"+this.title+",价格为:"+this.price;
}
}
public class Test{
public static void main(String[] args){
//引用了Book类的构造方法
IFun<Book> fun = Book :: new;
Book book = fun.create("java",29.8);
System.out.println(book);
}
}
4. java8中新的函数式接口包以及提供的四种函数式接口
对于方法的引用,严格来讲都需要定义一个接口,在Java8中提供了一个包:java.util.function
,并提供了一下四个核心接口:
- 功能型接口(Function):
Interface Function<T,R>{public R apply(T,t);}
|-此接口需要接收一个参数,并且返回一个处理结果 - 消费型接口(Consumer):
Interface Consumer<T>{public void accept(T t)}
|-此接口只负责接收数据(引用数据是不需要返回的),并且不返回处理结果 - 供给型接口(Supplier):
Interface Supplier<T>{public T get()}
|-此接口不接收参数,但是可以返回结果。 - 断言型接口(Predicate):
Interface Predicate<T>{public boolean test(T t)}
|-进行判断操作使用
由于jdk1.8当中存在上述四种功能接口,所以很少会由用户自己定义函数式接口