1.接口的默认方法
1.1传统的方法(之前的)
在java8之前java中接口里面的方法默认都是 public abstract 修饰的抽象方法并且没有方法体
1.2 static方法
- 使用static修饰接口中的方法并且必须有主体
- 接口的static方法只能被接口本身调用
- 接口的static方法不能被子接口继承
- 接口的static方法不能够被实现类覆写及直接调用
1.3 default方法
学习了上面的static方法之后,这里模仿来学习
- default方法必须有主体
- default方法可以被实现类覆写
- default方法可以被子接口继承
- default方法可以视作是接口定义时的初始化操作
2.函数式接口
2.1什么是函数式接口
函数式接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转化为lambda表达式
2.2函数式接口API
jdk1.8之前已有的函数式接口
- java.lang.Runnable
- java.util.concurrent.Callable
- java.util.Comparator
- java.io.FileFilter
- java.io.file.PathMatcher
- ...
jdk 1.8新增的函数接口
java.util.function 此包中包含了很多类,用来支持JAVA的函数式编程
2.3函数式接口注解
@functionalInterface
我们在函数式接口上面加上此注解后,里面就只能够有一个抽象方法了,当然不加此注解且只有一个抽象方法的接口也是函数式接口,只是没有限定提示而已。
3.Lambda表达式
3.1 什么是Lambda表达式
简单来说,可以看成是匿名内部类的简写,使用Lambda表达式时,接口必须是函数式接口(有且仅有一个抽象方法)。
3.2 Lambda表达式的语法
基本语法:
<函数接口名> <变量名> = (参数1,参数2...)->{
//方法体
}
特点说明:(参数1,参数2 ...)表示参数列表;
->表示连接符
{}内部是方法体
- =右边的类型会根据左边的函数式接口类型自动判断
- 如果形参列表为空,只需保留();
- 如果形参只有1个,()可以省略,只需要参数的名称即可
- 如果执行语句只有1句,且无返回值,{}可以省略,若有返回值,则若想省略{},则必须同时省略return,且执行语句也保证只有1句
- 形参列表的数据类型会自动判断
- lambda不会生成一个单独的内部类文件
- lambda表达式若访问了局部变量,则局部变量必须是final的,若是局部变量没有加final关键字,系统会自动添加,此后在修改该内部局部变量,会报错
3.3 Lambda学习案例代码
目录结构:
Myinterface文件:
MyinterfaceImpl文件:
Test文件:
package com.dhh.Lambda1;
import com.dhh.defaultMethod.ExtendInterfaceImpl;
public class Test {
public static void main(String[] args) {
//传统方式 创建一个MyInteferaceImpl类 然后调用对应的方法
MyInterface myInterface = new MyInteferaceImpl();
//不创建MyInteferaceImpl类,使用匿名内部类的方式,这样可以省略MyInteferaceImpl文件,在内部类里实现方法
MyInterface myInterface1 = new MyInterface() {
@Override
public int sum(int num1, int num2) {
return num1 + num2;
}
};
/**
* 使用Lambda表达式的方法
* 【常规写法】获取形参,方法体,用 -> 连接
**/
MyInterface myInterface2 = (int num1, int num2) -> {
return num1 + num2;
};
/**
* 使用Lambda表达式的方法
* 【简写】1.形参列表的数据类型可以省略,会自动匹配
* 2.如果方法中的代码只有一句,可以去掉{},如果是return返回数据的,那么可以省略return
*
**/
MyInterface myInterface3 = (num1, num2) -> num1 + num2;
System.out.println(myInterface3.sum(2, 4));
}
}
3.4 Lambda作用域-final
在Lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的某个字段以及静态变量。但如果访问局部变量,需要局部变量必须是final修饰的。
package com.dhh.Lambda2;
public class Test {
public static void main(String[] args) {
//定义一个局部变量
int age = 9;
MyInterface myInterface = ()-> System.out.println(age);
age = 10;
myInterface.printStr();
}
}
上面代码中,在Lambda表达式用了局部变量age,则age会自动加上修饰符final,在对age赋值10,代码就会报错。
4.方法引用
4.1 构造方法引用
1.准备一个Person类,提供一个两个参数的构造方法
package com.dhh.Lambda3;
public class Person {
private String firstName;
private String secondName;
public Person(String firstName, String secondName) {
super();
this.firstName = firstName;
this.secondName = secondName;
}
@Override
public String toString() {
return "Person{" +
"firstName='" + firstName + '\'' +
", secondName='" + secondName + '\'' +
'}';
}
}
2.准备一个personFactory接口
package com.dhh.Lambda3;
//获取person对象的工厂接口,也是函数式接口
public interface PersonFactory {
/**获得Person对象的方法**/
Person createPerson(String firstName,String secondName);
}
3.不同写法获得person对象
package com.dhh.Lambda3;
import com.dhh.Lambda2.MyInterface;
public class Test {
public static void main(String[] args) {
/*
*需求:
* 有一个person对象
* 有一个获得person对象的接口工厂
* 想通过工厂获得person对象
* 需要先有一个工厂对象
*/
//使用匿名内部类的方式
PersonFactory personFactory = new PersonFactory() {
@Override
public Person createPerson(String firstName, String secondName) {
return new Person(firstName,secondName);
}
};
//使用Lambda常规表达式
PersonFactory personFactory1 = (firstName,secondName)->new Person(firstName,secondName);
//使用Lambda表达式简单写法 构造方法引用(保证参数列表和构造参数方法列表一致)
PersonFactory personFactory2 = Person::new;
Person person = personFactory2.createPerson("kobe", "bryant");
System.out.println(person);
}
}
4.2 静态方法引用
1.准备一个函数式接口,提供一个解析字符串为int的方法
package com.dhh.Lambda4;
public interface ParseInterface {
/**将字符串解析成int**/
int parse(String str);
}
2.静态方法的引用
package com.dhh.Lambda4;
import com.dhh.Lambda2.MyInterface;
public class Test {
public static void main(String[] args) {
//匿名内部类 Integer.parseInt()为静态方法
ParseInterface parseInterface = new ParseInterface() {
@Override
public int parse(String str) {
return Integer.parseInt(str);
}
};
//Lambda表达式 常规写法
ParseInterface parseInterface1 = str->Integer.parseInt(str);
//Lambda表达式 简写【静态方法引用】 把参数原封不动给Integer调用parseInt方法
//与构造方法一致,参数未作任何处理继续给构造方法或静态方法调用,则可以采用引用方式
ParseInterface parseInterface2 = Integer::parseInt;
int parse = parseInterface.parse("123");
}
}
4.3 实例方法引用(了解,主要体会场景)
package com.dhh.Lambda5;
import com.dhh.Lambda4.ParseInterface;
import java.util.HashMap;
import java.util.function.Function;
public class Test {
public static void main(String[] args) {
/*
*需求:
* 已知String中有一个实例方法(非静态的)endswith
* 想自己写一个类封装这个方法
*
* 借助于jdk1.8的一个函数式接口function的apply方法(传入 T 返回 R)
* @FunctionalInterface
* public interface Function<T, R> {
* R apply(T var1);}
*
*/
//实例方法引用<T,R>指定数据类型
//调用者对象s 入参 hello,返回:boolean值
String s = "hello";
Function<String,Boolean> function = s::endsWith;
Boolean apply = function.apply(s);
System.out.println(apply);
}
}
小结:其实java8提供的Function函数式接口通用性非常强大,后续的学习会继续上传