接口增强
函数式编程之lambda表达式
方法引用与内建函数式接口
接口增强
java 8 以前接口只能包含抽象类和全局变量和静态变量,我们都知道实现接口的子类必须实现接口的所有抽象方法,这里就有一个问题出现了,如果某个接口有成千上万个实现类,某一天需要在这个接口新增一个方法,那么他的所有实现类就都得改.所有针对这一情况,从JDK1.8开始,允许在接口中使用default定义方法(普通方法,非抽象方法).
代码块1:
jdk1.8之前方框部分是不会编译通过的,不允许这样操作
代码块2:加上default 关键字以后
代码块3:
public interface Jdknew<T> {
String str="ssss";
void create();
default T get(T t){
return t;
}
}
public class App implements Jdknew<String> {
@Override
public void create() {
}
}
这类方法的调用方式:当成子类自己的普通方法一样通过实例对象调用即可
代码块4:
public class App implements Jdknew<String> {
@Override
public void create() {
}
public static void main(String[] args) {
App app = new App();
String str = app.get("哈哈");
System.out.println(str);
}
}
子类复写接口的default方法,并且调用复写的方法和接口的该方法:
代码块5:
public class App implements Jdknew<String> {
@Override
public void create() {
}
@Override
public String get(String t) {
//子类调用接口方法
String str= Jdknew.super.get(t);
System.out.println(str);
return t+"app";
}
public static void main(String[] args) {
App app = new App();
String str = app.get("哈哈");
System.out.println(str);
}
}
总结:重JDK1.8开始我们可以在接口中第一非抽象的方法(default修饰),同时子类不需要强制复写接口所定义的这类方法,当然有需要也可以重写,只是子类在调用接口方法的时候需要加上接口名称.
函数式编程:
函数式编程不是java的风格,当然这是JDK1.8 之前,现在可以以函数式编程方式写出更简洁,优雅,表达性更强,错误更少的代码.函数式编程的引进个人感觉就是让我们使用一些看是高级的的代码分格少些代码,但是在工作中使用较少,为啥?不习惯.当然说不定以后会流行起来.
lambda表达式:
拉姆达表达式常用于委托。也就是说拉姆达表达式是匿名函数.
代码块6:匿名内部类
public class App implements Jdknew<String> {
@Override
public void create(String t) {
}
public static void main(String[] args) {
Jdknew j=new Jdknew(){
@Override
public void create(Object o) {
System.out.println(o);
}
};
j.create("hello world");
}
}
代码块7:Lambda表达式
public class App implements Jdknew<String> {
@Override
public void create(String t) {
}
public static void main(String[] args) {
Jdknew j=(str) -> System.out.println(str);
j.create("hello world");
}
}
lambda 表达式方法体的使用形式:
①方法体只有一句: (参数) -> 程序语句 代码块7
②方法体有多行语句:(参数) -> { 程序语句 } 代码块8
③简单返回:(参数) -> 表达式 代码块9
代码块8:
public class App implements Jdknew<String> {
@Override
public void create(String t) {
}
public static void main(String[] args) {
Jdknew j=(str) -> {
System.out.println(str);
System.out.println(str+" 你好 世界");
};
j.create("hello world");
}
}
代码块9:
public interface Jdknew {
public int sum(int t1,int t2);
public static void main(String[] args) {
Jdknew j=(t1,t2) -> t1+t2;
System.out.println(j.sum(10, 20));
}
}
Lambda表达式的特殊接口:函数式接口
在lambda表达式的使用过程中会发现,如果在同一个接口中定义两抽象方法,在使用lambda表达式,就会编译报错了(代码块10),原因是lambda区分不了到底调的哪个接口.
代码块10:
JDK1.8 针对于lambda表达式新增@FunctionalInterface 注解,通过jdkdoc文档可以了解到这个注解具有以下几个特点:
①该注解只能标记在”有且仅有一个抽象方法”的接口上,就是说可以包含default修饰的方法和静态方法。
②接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
③该注解不是必须的如果符合函数式编程的接口,不符合在使用函数式编程会报错,加上便于编译检查
代码块11: 标准的函数式编程接口
@FunctionalInterface
public interface Jdknew<T> {
//抽象方法
public void method(T t);
//默认方法
default void method() {}
// static不是抽象方法
public static void staticMethod(){}
// java.lang.Object中的方法
public boolean equals(Object var1);
}
方法引用
方法引用的本质:用不同的方法名称表示不同的方法与对象的引用类似,设置不同的别名.从JDK1.8开始方法的引用主要分为以下几种方式:
①引用静态方法: 类名称 :: static 方法 代码块12
②对象方法引用: 实例化对象::方法名称 代码块13
③构造方法引用: 类名称::new 代码块14
代码块12: 引用静态方法
@FunctionalInterface
public interface Jdknew<P,R> {
//抽象方法
public R quotes(P p);
public static void main(String[] args) {
Jdknew<String,String> j=String :: toUpperCase;
String quotes = j.quotes("aaa");
System.out.println(quotes);
}
}
代码块13: 对象方法引
@FunctionalInterface
public interface Jdknew<R> {
//抽象方法
public R quotes();
public static void main(String[] args) {
Jdknew<String> j=new String("hello world"):: toUpperCase;
System.out.println(j.quotes());
}
}
代码块14: 构造方法引用
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
@FunctionalInterface
public interface Jdknew<P,R> {
//抽象方法
public R quotes(P p);
public static void main(String[] args) {
Jdknew<String,Person> j=Person:: new;
System.out.println(j.quotes("张三"));
}
}
在使用中发现需要使用lambda表达式实现方法引用,需要做很多无用的工作,比如要引用一个String的一个方法,就必须去定义一个函数接口.针对这些JDK1.8做了统一的处理在 java.util.function 这个包中做了相关的接口定义.可以根据参数情况和返回值情况选择相应的接口.