Java8 Interface Lambda
来源:互联网 发布:服装软件有哪些 编辑:程序博客网 时间:2024/06/03 19:38
Java是一门面向对象编程语言。面向对象编程语言和函数式编程语言中的基本元素(Basic Values)都可以动态封装程序行为:面向对象编程语言使用带有方法的对象封装行为,函数式编程语言使用函数封装行为。但这个相同点并不明显,因为Java的对象往往比较“重量级”:实例化一个类型往往会涉及不同的类,并需要初始化类里的字段和方法。
在Java8中接口也很多变化:
1、接口变量的访问
1) 局部变量:
- 从Java8开始,如果在内部类里面访问局部变量,会自动给局部变量加上final修饰
- Java8之前,内部类只能访问final的局部变量
2) 类变量:
内部类可以直接访问外部类变量,相当于是当前类访问一样。
3)实例变量:
- 如果在静态的方法里面写上匿名内部类,访问实例变量,必须通过外部类的实例来进行访问
- 如果外部类的实例是一个局部变量,该实例对应的变量不能多次赋值。但实例变量本身不会有影响
2、函数式接口 – Lambda的使用
函数式接口:当接口只有一个抽象方法的时候(可以有其它默认方法),就是函数式接口,可以使用注解(@FunctionalInterface)强制限定接口只能有一个抽象方法。
lambda语法:
([形参列表,不带数据类型]) -> { // 执行语句 [return ...;]}
其中:
() : 表示参数列表,不需要指定参数类型,会自动推断
-> : 连接符
{} : 表示方法体
注意点:
- 1.如果形参列表是空的,只需要保留()即可。
- 2.如果没有返回值,只需要在{}写执行语句即可。
- 3.如果接口的抽象方法只有一个形参,()可以省略,只需要参数的名称即可
- 4.如果执行语句只有一行,可以省略{},但是如果有返回值的时候,不能省略
- 5.形参列表的数据类型自动推断,只要参数名称
- 6.如果函数式接口的方法有返回值,必须要给定返回值,如果执行语句只有一行代码,可以省略大特号,但必须同时省略return关键字
lambda表达式就是函数式接口,也可以认为是一种特殊的匿名内部类。下面就看看匿名内部类的lamdba表达式的写法:
1) 方法无参数,无返回值
public class LambdaDemo { public static void main(String[] args) { // 1. 匿名内部类的方式实现,在Java8之前,没有Lambda表达式 UserService userService = new UserService() { @Override public void test() { System.out.println("不使用lambda表达式"); } }; userService.test(); // lambda 右边的类型,会自动根据左边的变量的类型进行推断 UserService userService1 = () -> { System.out.println("使用lambda表达式"); }; userService1.test(); // lambda 如果方法体只有一句话,可以省略大括号以及省略一个分号 // 如果有返回值,连return也可以省略 UserService userService2 = () -> System.out.println("使用最简lambda表达式"); userService2.test(); }}@FunctionalInterface// 没有参数,没有返回值interface UserService{ void test();}
Result:
2) 有一个参数,无返回值
public class LambdaDemo { public static void main(String[] args) { // 2 方法有一个参数,园括号里面只需要知道参数的名称,不需要参数的类型。 // 数据类型自动根据函数式接口的定义自动推断 UserService1 test1 = (x) -> { System.out.println("一个参数,一行代码输出参数的值 : " + x); }; test1.test(100); // 如果参数列表里面,只有一个参数,可以省略园括号 UserService1 test2 = x -> System.out.println("一个参数,一行代码输出参数的值 : " + x); test2.test(100); }}@FunctionalInterface// 有一个参数,没有返回值interface UserService1{ void test(int i);}
3) 有二个参数,没有返回值
public class LambdaDemo { public static void main(String[] args) { UserService2 test3 = (x, y) -> { System.out.println("两个参数 : " + x); System.out.println("两个参数 : " + y); }; test3.test(100, 200); }}@FunctionalInterface// 有二个参数,没有返回值interface UserService2{ void test(int i, int j);}
4) 有一个参数,有返回值
public class LambdaDemo { public static void main(String[] args) { // 4 有返回值 UserService3 test4 = b -> { b = b + 10; return b; }; int o = test4.test(15); System.out.println(o); // 如果省略大括号,return一定要省略掉。代码里面的表达式返回值会自动作为方法的返回值 UserService3 test5 = b -> b + 10; System.out.println(test5.test(15)); }}@FunctionalInterface// 有一个参数,有返回值interface UserService3{ int test(int i);}
3、方法的引用 – Lambda的使用
1) 引用实例方法
public class TestMethodRef { public static void main(String[] args) { MethodRef r = s -> System.out.println(s); r.test("字符串的"); // 使用方法的引用 : 实例方法的引用 // System.out是一个实例 MethodRef r1 = System.out :: println; r1.test("方法引用"); }}@FunctionalInterfaceinterface MethodRef{ void test(String s);}
2) 引用类方法
public class TestMethodRef { public static void main(String[] args) { // 能够根据函数式接口的方法参数,推断引用的方法的参数的数据类型 // 不引用方法进行排序 MethodRef1 r3 = (o) -> Arrays.sort(o); // 引用类方法 MethodRef1 r2 = Arrays :: sort; int[] a = new int[]{4, 12, 32, 44, 5, 9}; // 引用方法排序 r2.test(a); // 引用方法输出 r1.test(Arrays.toString(a)); }}@FunctionalInterfaceinterface MethodRef1{ void test(int[] arr);}
3) 引用类实例方法
public class TestMethodRef { public static void main(String[] args) { // *** 引用类的实例方法 MethodRef2 r4 = PrintStream :: println; // 第二个之后的参数,作为引用方法的参数 r4.test(System.out, "第二个参数"); }}@FunctionalInterfaceinterface MethodRef2{ void test(PrintStream out, String str);}
4) 引用构造器
public class TestMethodRef { public static void main(String[] args) { // 引用构造器,根据函数式接口的方法名来推断引用哪个构造器 MethodRef4 r5 = String :: new; String ok = r5.test(new char[]{'阿' , '器'}); System.out.println(ok); MethodRef4 r6 = (c) -> {return new String(c);}; String o1 = r6.test(new char[]{'阿' , '器'}); System.out.println(o1); }}// 测试构造器引用@FunctionalInterfaceinterface MethodRef4{ String test(char[] str);}
4、接口中的静态方法
从java8开始接口里面可以有静态方法(之前接口中是不能定义静态方法的),和普通类里面的静态方法类似,使用static修饰,但是接口里面的只能是public的。格式为:
[public] static <返回值> <方法名> ([形参列表]){ // 方法体}
例子如下:
public interface TestStaticMethod { // 这是一个函数式接口,因为这个接口里面只有一个抽象方法 public void test(); // 静态方法不是抽象方法 static void test1(){ System.out.println("这个是接口里面的静态方法,直接可以使用接口调用此方法"); } public static void main(String[] args) { System.out.println("自从接口可以有静态方法,从此接口可以写main方法,可以作为程序的入口"); TestStaticMethod.test1(); }}class TestStaticMethodClass{ public static void main(String[] args) { // 调用接口的静态方法 TestStaticMethod.test1(); }}
5、接口中的默认方法
在Java8中除了可以在接口里面写静态方法,还可以写非静态方法,但是必须用default进行修饰。
public interface TestDefaultMethod { // 使用 default 修改的方法,表示实例方法, 必须通过实例来方法 public default void test(){ System.out.println("这个是接口里面的默认方法" + this); } public static void main(String[] args) { // 使用匿名内部类初始化实例 TestDefaultMethod tdm = new TestDefaultMethod() {}; // 使用对象来访问默认方法 tdm.test(); }}
Result:
接口中可以使用this关键字,但是我们可以看到结果中有$,这是不是和我们的匿名内部类有点像了?
注意:
- 默认方法可以被继承。如果继承多个父接口有重复的默认方法被继承到子接口,必须使用super引用明确指定调用哪个接口的默认方法在子接口必须重写重复方法,并使用下面的语法重写父接口方法重复的问题
<父接口类名>.super.<重复的方法名>([参数]);
- 同样,如果实现了多个接口,遇到有重复的默认方法,也需要使用重写重复的方法,使用super引用解决问题,和接口一样。
- 父接口的抽象方法,在子接口里面可以使用默认方法实现,这样是实现类里面就不需要再实现了。如果实现类再去实现默认方法,那么相当于是”方法覆盖”。
- 如果父接口有一个抽象方法,在子接口里面可以重写为抽象方法(去掉父接口的形为)
1) 默认方法多继承
interface A{ default void test(){ System.out.println("接口A里面的默认方法"); }}interface B{ default void test(){ System.out.println("接口B里面的默认方法"); }}public interface C extends A, B { // 明确指定引用父接口,使用super引用调用父接口的默认方法 // <父接口类名>.super.<重复的方法名>([参数]) default void test(){ B.super.test(); System.out.println("接口C重写的默认test方法"); }}
如果注释掉C接口中的test方法就会报以下的错误:
Test
class Test{ public static void main(String[] args) { C c = new C(){}; c.test(); }}
Result:
2) 默认方法的重写
public interface E { default void test(){ System.out.println("默认方法"); }}interface F extends E{ // 在子接口重写父接口的默认方法,把默认方法改为抽象方法 void test();}class RemoveDefaultMethod { public static void main(String[] args) { E e = new E(){}; e.test(); F f = () -> System.out.println("匿名内部类重写父接口方法"); f.test(); }}
Result:
推荐阅读: 深入理解Java 8 Lambda
- Java8 Interface Lambda
- java8 lambda 使用 与 functional interface 与 function 类
- java8 Lambda
- Java8 Lambda
- Java8 Lambda
- java8 lambda
- java8-lambda
- java8-lambda
- java8 Lambda
- 【lambda】java8 lambda
- Java8 Lambda表达式教程
- Java8 Lambda表达式教程
- Java8: Lambda表达式语法
- java8 Lambda表达式
- Java8 Lambda表达式教程
- Java8 Lambda表达式
- java8 Lambda表达式
- Java8 Lambda表达式教程
- 在三维空间里创建10个物体,并可以自由缩放,移动视角
- bios boot option 找不到u盘
- 取尺法 和区间调度
- python之列表推导式及嵌套列表解析学习
- 这个计算机网络= =
- Java8 Interface Lambda
- 安卓基础笔记2之SQLit数据库
- Android的ion相关学习(二)
- 解决My eclipse 工程发布时端口占用问题
- java插入数据后返回新插入数据的id字段(自增)
- 微信小程序填坑之路(四)--2016.12.21 更新
- Union和Union All到底有什么区别
- 与MySQL传统复制相比,GTID有哪些独特的复制姿势?
- IntelliJ IDEA 使用详解