```java
public interface Formula {
//计算
public double calculate(int a);
//开方
default double sqrt(int a){
return Math.sqrt(a);
}
}
main:
Formula f = new Formula() {
@Override
public double calculate(int a) {
return a+1;
}
};
System.out.println(f.calculate(4));
System.out.println(f.sqrt(8));
//注意:现在接口还可以存在静态方法,可以使用 接口名.静态方法名 的形式直接调用
2.Lambda 表达式
认识Lambda表达式
例如:
```java
```java
public class LambdaTest1 {
public static void main(String[] args) {
//假如一个list机会中的元素要排序
List<String> list = Arrays.asList("hello","tom","apple","bbc");
//之前的排序我们可以这样写
Collections.sort(list, new Comparator<String>(){
@Override
public int compare(String o1, String o2) {
return -o1.compareTo(o2);
}
});
//使用Lambda表达式
Collections.sort(list,(String s1,String s2)->{
return s1.compareTo(s2);
});
//可以简写为
//1.大括号里面就一句代码
//2.编译器可以自动推导出参数类型
Collections.sort(list,(s1,s2)->s1.compareTo(s2));
System.out.println(list);
}
}
Functional接口
"函数式接口"是指仅仅只包含一个抽象方法的接口,每一个函数式接口类型的lambda表达式都会自动被匹配到这个抽象方法。因为 默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。
我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,为了确保你的接口确实是达到这个要求的,可以接口上添加 @FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
例如:
//这个注解不加也可以,加上只是为了让编译器检查
@FunctionalInterface
interface Action{
public void run();
default void doSomething(){
System.out.println("doSomething..");
}
}
//这个注解不加也可以,加上只是为了让编译器检查
@FunctionalInterface
interface Work<T,V>{
public V doWork(T t);
}
public class LambdaTest2 {
public static void test(Action a){
a.run();
a.doSomething();
}
public static void run(Work<String,Integer> a){
int i = a.doWork("hello");
System.out.println(i);
}
public static void main(String[] args) {
//原来的内部类实现方式
test(new Action(){
@Override
public void run() {
System.out.println("run..");
}
});
//lambda表达式方法
test(()->System.out.println("run"));
//也可以先创建对象
Action a = ()->System.out.println("run...");
System.out.println(a.getClass());
test(a);
//接口中有泛型也可以,只关注方法的参数和返回值
Work<String,Integer> w = (v)->v.length();
run(w);
run((v)->v.length());
//如果参数只有一个,那么还可以这样简写: 去掉小括号
//注意代码就一句,作为返回值的话不用写return
run(v->v.length());
//有多句代码,就需要写{}了,并且需要写return
run(v->{
System.out.println("doWork..");
return v.length();
});
//观察下面代码是什么意思
run(v->1);
}
}
注意:lambda表达式无法表示接口中默认方法的重写,lambda表达式只能去匹配对应接口中的唯一抽象方法。相当于lambda表达式只是对抽象方法的实现。
Java 8 允许你使用 :: 关键字来传递方法(静态方法和非静态方法)
例如:
public class LambdaTest3 {
public static void main(String[] args) {
//正常是这样使用的
Action3 a1 = v->"接收的数字为:"+v;
System.out.println(a1.run(5));
//使用Lambda引用Integer类中的静态方法
Action3 a2 = Integer::toBinaryString;
System.out.println(a2.run(10));
//使用Lambda引用LambdaTest3类的对象中的非静态方法
LambdaTest3 t = new LambdaTest3();
Action3 a3 = t::test;
System.out.println(a3.run(20));
}
public String test(int i){
return "i="+i;
}
}
@FunctionalInterface
interface Action3{
public String run(int i);
}
注:相当于使用lambda表达式引用另一个类中方法的实现来作为Action3接口中run方法的实现,前提是俩个方法的参数列表和返回类型必须一致
能引用Integer类中的静态方法toBinaryString的原因是:Action3接口中只有一个方法且方法的参数类型和返回值类型与Integer类中的静态方法toBinaryString的参数类型、返回类型是一致的.那么能引用非静态方法的原因也是这样。
下面是一个接口中带泛型的时候例子: 可以使用 类名::非静态方法 的形式引用方法
注意:没有泛型的时候都也使用
public class LambdaTest3Pro {
public static void main(String[] args) {
Model m = new Model();
//这些写法都可以
//相当于变量v是run方法中接收的形参,然后使用v调用它的方法,v的类型是Model,因为这里使用了泛型
Action3Pro<Model> a1 = v->v.test1();
Action3Pro<Model> a1 = v->v.test2("hello");
Action3Pro<Model> a1 = v->v.test3();
a1.run(m);
//在这种情况下,还可以使用Model引用它的内部的方法
//但是必须满足以下要求:
//1.run方法参数类型【必须】Model
//2.引用的方法【必须】是无参的
//将来run方法中就自动会调用所传的对象m这个被引用的方法
Action3Pro<Model> a2 = Model::test1;
a2.run(m);
或者
Action3Pro<Model> a2 = Model::test3;
a2.run(m);
//编译报错,因为test2不是无参的
Action3Pro<Model> a2 = Model::test2;
a2.run(m);
}
}
interface Action3Pro<T>{
public void run(T t);
}
class Model{
public void test1(){
System.out.println("test1");
}
public void test2(String s){
System.out.println("test2");
}
public int test3(){
System.out.println("test3");
return 1;
}
}
public class LambdaTest4 {
public static void main(String[] args) {
//Lambda表达式引用构造函数
//根据构造器的参数来自动匹配使用哪一个构造器
//这里执行create方法的时候会自动调用Action4类中的有参构造器
Action4Creater a = Action4::new;
Action4 a4 = a.create("zhangsan");
a4.say();
}
}
class Action4{
private String name;
public Action4() {
}
public Action4(String name) {
this.name = name;
}
public void say(){
System.out.println("name = "+name);
}
}
interface Action4Creater{
public Action4 create(String name);
}