一、接口的默认方法、static方法、default方法。
1、接口的默认方法
在Java8之前,Java中接口里面的默认方法都是public abstract 修饰的抽象方法,抽象方法并没有方法实体。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Test_interface { public static void main(String[] args) { pubInterface ts = new MyInterface(); ts.fun1(); } } //测试接口 interface pubInterface{ public void fun1();//抽象方法 } //接口的实现类 class MyInterface implements pubInterface{ @Override public void fun1() { System.out.println("你好我是TestStatic的实现类"); } }
2、static方法
在Java8中,接口里面可以用static修饰有方法实体的方法。
(1)、使用static修饰的接口中的方法必须要有实体。
(2)、接口的static方法只能够被接口本身调用:接口名.方法名(…)。
(3)、接口的static方法不能够被子接口继承。
(4)、接口的static方法不能够被实现类重写或者调用。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Test_interface { public static void main(String[] args) { //该接口直接可以调用static方法,但是不能够调用普通抽象方法。 StaInterface.fun2(); //报错可以得知,static方法是不能够被继承的 SonInterface.fun2(); } } //测试接口 interface StaInterface{ public void fun1();//抽象方法 static void fun2(){ System.out.println("我是static方法……"); } } //接口的实现类 class MyInterface implements StaInterface{ /**只能够重写抽象方法,不能重写static修饰的方法*/ @Override public void fun1() { } } //子接口 interface SonInterface extends StaInterface{ }
3、default方法:
接口的default方法必须有主体
接口的default方法不能被本身接口调用,
接口的default方法可以被子接口继承
接口的default方法可以被实现类复写以及调用
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Test_interface { public static void main(String[] args) { //该接口直接可以调用static方法,但是不能够调用普通抽象方法。 StaInterface.fun2(); //报错可以得知,static方法是不能够被继承的 SonInterface.fun2(); //default方法与普通抽象方法是可以 StaInterface sf = new MyInterface(); sf.fun1(); sf.fun3(); } } //测试接口 interface StaInterface{ public void fun1();//抽象方法 //static 方法 static void fun2(){ System.out.println("我是static方法……"); } //default方法 default void fun3(){ System.out.println("我是default方法……"); } } //接口的实现类 class MyInterface implements StaInterface{ /**只能够重写抽象方法,不能重写static修饰的方法*/ @Override public void fun1() { } //是可以重写default方法的。 @Override public void fun3() { } } //子接口 interface SonInterface extends StaInterface{ }
二、函数式接口
1、什么是函数式接口:
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为lambda表达式。
接口注解:@FunctionalInterface
初体验:
(1)、两个参数,有返回值
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Lambda_one { public static void main(String[] args) { //匿名内部类的方式 StaInterface se = new StaInterface() { @Override public int sum(int num1, int num2) { return num1 +num2; } }; System.out.println(se.sum(1,3)); //lambda表达式写法 StaInterface seLa1 = (int num1, int num2) -> { return num1 + num2; }; System.out.println("Lambda表达式一:" + seLa1.sum(1,3)); /** * lambda表达式简写 * 1、形参列表中的表达式可以不写,会自行推断 * 2、如果方法体中的代码只有一句,可以省略{},如果return返回的是数据,可以省略return */ StaInterface seLa2 = (num1, num2) -> num1 + num2; System.out.println("Lambda表达式二:" + seLa2.sum(1,2)); } } //测试接口 @FunctionalInterface interface StaInterface{ public int sum(int num1,int num2);//抽象方法 }
(2)、一个参数,无返回值
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Lamdba_two { public static void main(String[] args) { //匿名内部类 StaInterface1 s1 = new StaInterface1() { @Override public void getStr(String str) { System.out.println(str); } }; s1.getStr("HelloWorld!!!"); //lambda表达式写法 StaInterface1 s2 = (String str) -> { System.out.println(str); }; s2.getStr("Lambda表达式一:"+ "Helloworld一"); StaInterface1 s3 = str -> System.out.println(str); s3.getStr("Lambda表达式二:"+ "Helloworld二"); } } //测试接口 @FunctionalInterface interface StaInterface1{ public void getStr(String str);//抽象方法 }
(3)、无参数,无返回值
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Lambda_three { public static void main(String[] args) { StaInterface2 s1 = new StaInterface2() { @Override public void getStr() { System.out.println("HelloWorld"); } }; s1.getStr(); //Lambda表达式 StaInterface2 s2 = () -> { System.out.println("Lamdba表达式一:" + "HelloWorld一"); }; s2.getStr(); //Lamdba表达式简化,我们可以这么写,但是没有实际意义 StaInterface2 s3 = () -> {}; s3.getStr(); } } //测试接口 @FunctionalInterface interface StaInterface2{ public void getStr();//抽象方法 }
三、Lambda表达式
1、什么是Lambda表达式
简单的说:可以看成是对匿名内部类的简写,使用Lambda表达式时候,接口必须是函数式接口。
2、Lambda表达式语法
基本语法:
<函数式接口> <变量名> = (参数1,参数2……)->{
//方法体
}
3、特点:
(1)、=右边的类型会根据左边的函数式接口类型自动推断;
(2)、如果形参列表为空,只需要保留()
(3)、如果形参只有一个,()可以省略,只需要参数名称即可;
(4)、如果执行语句只有一句,且并没有返回值,{}可以省略,如果有返回值,若想省去{},则必须同时省略return,并且执行语句也保证只有一句。
(5)、形参列表的数据类型会自动推断。
(6)、Lamdba不会生成一个单独的内部类文件。
(7)、lambda表达式如果访问了局部变量,则局部变量必须是final的,若是局部变量没有加final关键字,系统会自动添加,此后在修改局部变量,会报错。
4、Lambda作用域
在Lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似(我们在学习匿名内部类时候,匿名内部类在访问局部变量的时候,局部变量是被final修饰的),你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量,但是如果访问局部变量,要求局部变量必须是final修饰的。
注意:我们Java8新特性里面,匿名内部类访问局部变量,局部变量不需要再用final修饰了,因为Java8已经帮我们写过了,所以我们可以省略。
(1)、匿名内部类举例
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Lambda_four { public static void main(String[] args) { int age = 9; StaInterface3 s1 = new StaInterface3() { @Override public void getStr() { System.out.println(age); //注意,当我们在下面对age重新赋值时候,这里的age就报错了, // 因为,Java8隐式的对age加上final了 } }; s1.getStr(); age = 10; } } interface StaInterface3{ public void getStr();//抽象方法 }
(2)、Lambda表达式举例
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Lambda_four { public static void main(String[] args) { int age = 9; StaInterface3 s2 = () ->{ System.out.println(age); //注意,当我们在下面对age重新赋值时候,这里的age就报错了, // 因为,Java8隐式的对age加上final了 }; age = 10; } } interface StaInterface3{ public void getStr();//抽象方法 }
四、方法的引用
1、构造方法的引用
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Lambda_five { /*需求: * 1、有一个Person类 * 2、有一个获得Person对象的接口工厂 * 3、想通过工厂获得一个Person对象 * 4、需要现有一个实际的工厂对象 */ public static void main(String[] args) { //使用匿名内部类 PersonFactory py = new PersonFactory() { @Override public Person createPerson(String firstName, String lastName) { return new Person(firstName,lastName); } }; Person person1 = py.createPerson("du", "yahui"); System.out.println(person1); //使用Lambda表达式 PersonFactory py1 = (firstName,lastName) ->{ return new Person(firstName,lastName); }; Person person2 = py1.createPerson("mi", "li"); System.out.println(person2); //简写Lambda表达式 PersonFactory py2 = (firstName,lastName) -> new Person(firstName,lastName); Person person3 = py2.createPerson("haha","gaga"); System.out.println(person3); } }
2、静态方法的引用,把String转成num
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Lambda_six { public static void main(String[] args) { ParseLambda pa = new ParseLambda() { @Override public int parseInteger(String num) { return Integer.parseInt(num); } }; int i1 = pa.parseInteger("12"); System.out.println(i1); //使用Lambda表达式 // ParseLambda p = (String num) ->{ // return Integer.parseInt(num); // }; ParseLambda pa1 = num -> Integer.parseInt(num); int i2 = pa1.parseInteger("123"); System.out.println(i2); //Lambda简写 ParseLambda pa3 = Integer :: parseInt; int i3 = pa3.parseInteger("777"); System.out.println(i3); } } interface ParseLambda{ int parseInteger(String num); }
五、四大核心函数式接口
/* * Java8 内置的四大核心函数式接口 * * Consumer<T> : 消费型接口 * void accept(T t); * * Supplier<T> : 供给型接口 * T get(); * * Function<T, R> : 函数型接口 * R apply(T t); * * Predicate<T> : 断言型接口 * boolean test(T t); * */ public class Lambda_One { //Consumer<T> 消费型接口 :也就是,给一个参数,操作这个参数 @Test public void test1(){ happy(1000,(money) -> System.out.println("出去共消费了" + money + "元")); } public void happy(double money, Consumer<Double> con){ con.accept(money); } //Supplier<T> 供给型接口 :产生一些对象 @Test public void test2(){ List<Integer> listNum = getListNum(10,() -> (int)(Math.random() * 100)); for (Integer integer : listNum) { System.out.println(integer); } } //需求:产生指定个数的整数,并放入集合中 public List<Integer> getListNum(int num, Supplier<Integer> sup){ List<Integer> list = new ArrayList<Integer>(); for(int i = 0; i < num; i++){ list.add(sup.get()); } return list; } //Function<T, R> 函数型接口:传入一个T,返回一个R @Test public void test3(){ String s1 = stringHander(" Helloworld !!!",(str) -> str.trim()); System.out.println(s1); String s2 = stringHander(" Helloworld !!!",(str) -> str.substring(7)); System.out.println(s2); } //需求:处理字符串 public String stringHander(String str, Function<String,String> fun){ return fun.apply(str); } //Predicate<T> 断言型接口:用于做一下判断 @Test public void test4(){ List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok"); List<String> listStr = filterStr(list,(str) -> str.length() > 3); for (String s : listStr) { System.out.println(s); } } //需求:将满足条件的字符串,放入集合中 public List<String> filterStr(List<String> list, Predicate<String> pre){ List<String> strList = new ArrayList<>(); for (String str : list) { if(pre.test(str)){ strList.add(str); } } return strList; } }
其他接口: