目录
- 一、关于接口的新特性
- 1.1 jdk1.8之前的接口重要特性
- 1.2 JDK8以后
- 代码演示
- 1.3 总结
- 通过代码演示发现
- 作用
- 二、Lambda表达式[重点]
- 2.1 将匿名内部类写法改写为lambda写法
- 2.2 语法特点
- 能够写成lambda形式的的前提
- 语法特征
- 代码演示
- 深入理解lambda
- 2.3 总结
- 三、函数式接口
- 3.1 概念
- 什么是函数式接口
- 四个典型的函数式接口
- 3.2 Supplier
- 3.3 Consumer
- 3.4 Function
- 3.5 Predicate
- 3.6 总结
- 思维导图
- 最后
一、关于接口的新特性
1.1 jdk1.8之前的接口重要特性
- 方法全都是抽象方法,即都没有方法体
1.2 JDK8以后
- 允许接口中有被default和static修饰的方法带方法体
代码演示
接口USB
public interface USB {/** jdk8之前接口中只能有抽象方法* jdk8之后接口中被default的方法不是抽象方法,可以被重写,也可以不重写,不强制* 且方法还可以被static修饰,不能被重写,调用,只能通过接口调用*/int a =1;void fun1();// 默认抽象方法default void funNew(){// 被default修饰方法System.out.println("JDK8新特性:default修饰的方法要有方法体,实现类不强制重写");}static void funNew2(){// 被static修饰方法System.out.println("JDK8新特性:static修饰的方法要有方法体,实现类不可重写,不可调用,通过接口直接调用");}
}
实现类USBImpl
public class USBImpl implements USB{@Overridepublic void fun1() {System.out.println("重写旧方法");}@Overridepublic void funNew() { //可以重写default修饰的方法}}
测试
public class USBImplTest {public static void main(String[] args) {USBImpl usb = new USBImpl();usb.fun1();usb.funNew();//usb.funNew2(); //实现类无法调用USB.funNew2();// 通过接口调用静态方法}
}
1.3 总结
通过代码演示发现
- jdk8之后接口中被default的方法不是抽象方法,可以被重写,也可以不重写,不强制
- 且方法还可以被static修饰,不能被重写,调用,只能通过接口调用
作用
- 默认方法允许在不破坏现有实现的情况下向接口添加新功能。
- 可以在不改变现有用户代码的情况下扩展接口。
- 促进了API的演进,同时保持了向后的兼容性。
二、Lambda表达式[重点]
Lambda是匿名内部类的简化
Lambda 允许把函数(方法)作为一个方法的参数(函数作为参数传递到方法中)。
其实就是简化了匿名内部类的写法,更准确的说是对接口方法的重写的简化
2.1 将匿名内部类写法改写为lambda写法
使用lambda改写创建线程的方式
public static void main(String[] args) {new Thread(new Runnable( ) {@Overridepublic void run() {for (int i = 0; i < 10001; i++) {System.out.println("正常实现Runnable完成线程" + i);}}}).start( );// 改成lambda形式// lambda是简化了匿名内部类,只剩下关于方法的参数列表和方法体// () -> {}new Thread(() -> {for (int i = 0; i < 10001; i++) {System.out.println("lambda完成线程"+i);}}).start( );// lambda是将方法当参数传递给另外一个方法}
}
2.2 语法特点
能够写成lambda形式的的前提
- 方法得有参数
- 参数的必须是接口
- 接口中的方法有且只能有一个!!!
语法特征
(参数) -> {执行语句}
或者
参数 -> 执行语句
参数圆括号,当参数是一个的时候,圆括号可加可不加
- (x) -> System.out.println(x)
- x -> System.out.println(x)
参数圆括号,当参数是多个的时候,圆括号必须加
- (x,y) -> System.out.println(x+y)
参数数据类型可写可不写,编译时会自动推断是什么类型
- (x,y) -> System.out.println(x+y)
- (int x,String y) -> System.out.println(x+y)
执行语句的花括号,当且仅当执行语句只有一句时,可以不加花括号
new Thread(() -> System.out.println("匿名内部类开启线程")).start();
执行语句的花括号,当执行语句不只一句时,必须加花括号
new Thread(() -> {int a = 1;a++;System.out.println("lambda开启线程" );}).start();
关于返回值
如果方法有返回值,且执行语句只有一行语句时,可以不用写return,直接写值
test(() -> {return 1;}); test(() -> 1);// 1就是return1
如果代码比较多,又要返回数据,就必须写上return
test(() -> {int a = 1;a++;return a; });
代码演示
ppublic class lambdaTest {/*1. **方法得有参数**2. **参数的必须是接口**3. **接口中的方法有且只能有一个!!!***/public static void main(String[] args) {// 如果lambda方法体中只有一行代码,{}可以省略show1(() -> System.out.println("无参无返回值"));// 如果lambda方法体中有多行代码,{}不能省略show1(() -> {System.out.println("无参无返回值1");System.out.println("无参无返回值2");System.out.println("无参无返回值3");});/** 有参数列表时,参数类型可以省略*/// 只有一个参数,()可以省略show2(b1 -> System.out.println(b1 * 10));// 参数数量>1,()不可以省略show3((c1,c2)->System.out.println(c1 + c2));// 有返回值,但是只有一行代码,{}可以省略,return也可以省略,-> 跟的就是返回值show4(d -> d);}//接口IA为参数,IA只有一个方法static void show1(IA ia){ia.a();}//接口IB为参数,IB只有一个方法static void show2(IB ib){ib.b(1);}//接口IC为参数,IC只有一个方法static void show3(IC ic){ic.c(1,2);}//接口ID为参数,ID只有一个方法static void show4(ID id){id.d(10);}
}
// 接口:IA只有一个无参无返回值方法
interface IA{void a(); //无参无返回值
}// 接口:IA只有两个个无参无返回值方法
interface IC{void c(int c1,int c2); //参无返回值
}// 接口:IA只有一个无参无返回值方法
interface IB{void b(int b); //无参无返回值
}// 接口:IA只有一个无参无返回值方法
interface ID{int d(int a); //无参无返回值
}
深入理解lambda
为什么lambda要设计成,将方法(功能) 当参数传递给方法
- 有了lambda,方法的功能不再局限,方法具体如何,要看看lambda功能如何
public class Demo3 {public static void main(String[] args) {double add = add(1, 2);System.out.println("add = " + add);double yunsuan = yunsuan((x, y) -> x / y, 1, 2);System.out.println("yunsuan = " + yunsuan);}/*** 已经的方法,参数列表是普通变量* 方法功能已经定好,唯一变化的是参数的值* 例如,这个add方法,是做两数相加,只能相加* 唯一能变的是,加的数不一样* --------------------------* 那如果,我想传入两个参数,让其相除返回结果?让其相乘返回结果?* 就需要重新设计方法*/public static double add(int a,int b){return a + b;}/*** 有了lambda之后,方法的执行功能就不再固定* 如何运行,要看调用时,传入的lambda是如何运行的*/public static double yunsuan(IE e,int a,int b){return e.jisuan(a, b);}}
interface IE {double jisuan(int a,int b);
}
2.3 总结
- 其实 () -> {}
()
里面放的是重写方法的参数{}
里面放的是重写方法的方法体- 上面各种写法只是在特定情况下的简写,没有特定条件是没法简写的,就要按部就班来
- lambda就是简化了匿名内部类的写法
- lambda其实就是接口方法的重写
- lambda的参数和返回值是根据接口方法决定的
三、函数式接口
3.1 概念
什么是函数式接口
接口中只有一个抽象方法时,该接口就是函数式接口
.
Java提供了一个注解可以校验接口是否是函数式接口
@FunctionalInterface
Java中提供了几个特别常用的函数式接口
- Supplier 供应,即返回一个数据 (无参有返回值的方法)
- Consumer 消费,即给其传入数据做运算 (有参无返回值的方法)
- Function 函数,传入2个参数,用于转换数据的 (有参有返回值的方法)
- Predicate 判断,返回时boolean (有参,返回值是boolean)
四个典型的函数式接口
3.2 Supplier
- Supplier.java源码
@FunctionalInterface
public interface Supplier<T> {/*** Gets a result.** @return a result*/T get();
}
// 该接口用来返回一个数据,所以叫供应商
// 其实就是无参数有返回值的接口,用的时候就是无参有返回值的lambda
练习,设计方法,通过Supplier接口,获得字符串的长度
/** Supplier接口 ---顾名思义:供应,提高* 提供的方法--- T get();* 不需传入参数,就有返回值*///利用Supplier接口,实现获得字符串长度功能int i = get(() -> "java".length());System.out.println("i = " + i);// i = 4//参数为Supplier接口的方法public static int get(Supplier<Integer> supplier){return supplier.get();}
3.3 Consumer
JDK中Consumer.java源码
@FunctionalInterface
public interface Consumer<T> {/*** Performs this operation on the given argument.* 给传入一个值,对该值进行操作* @param t the input argument*/void accept(T t);
}
// 其实就是有参数无返回值的接口,用的时候就是有参无返回值的lambda
练习:设计方法,传入字符串,将字符串全部转大写,后输出
/** Consumer接口 ---顾名思义:消费,消耗* 提供的方法--- void accept(T t);* 需传入参数,无返回值*///利用Consumer接口,实现字符串转大写功能String s = "java";accept(c -> System.out.println(c.toUpperCase()),s);// JAVA//参数为Consumer接口的方法public static void accept(Consumer<String> consumer,String s){consumer.accept(s);}
3.4 Function
JDK中Function.java源码
@FunctionalInterface
public interface Function<T, R> {/*** Applies this function to the given argument.** @param t the function argument* @return the function result*/R apply(T t);
}
// 该接口用于,转换数据
// 其实就是有参数有返回值的接口,用的时候就是有参有返回值的lambda
利用Function,实现字符串数字转为整形数字功能
/** Function<T, R>接口 ---顾名思义:函数,功能* 提供的方法--- R apply(T t);* 将T转换乘R类型 ,即转换数据*///利用Function,实现字符串数字转为整形数字功能String s2 = "111";Integer apply = apply(f -> Integer.parseInt(f), s2);System.out.println("apply = " + apply);// apply = 111//参数为Function接口的方法public static Integer apply(Function<String,Integer> function,String s){return function.apply(s);}
3.5 Predicate
JDK中Predicate.java源码
@FunctionalInterface
public interface Predicate<T> {/*** Evaluates this predicate on the given argument.** @param t the input argument* @return {@code true} if the input argument matches the predicate,* otherwise {@code false}*/boolean test(T t);
}
判断数据是否是偶数
/** Predicate接口 ---顾名思义:判断,断定* 提供的方法--- boolean test(T t);* 提供判断方法*///利用Predicate接口,实现判断是否时偶数功能int i1 = 2;boolean b = predicate(a -> a % 2 == 0, i1);System.out.println("b = " + b); // b = true//参数为Predicate接口的方法public static boolean predicate(Predicate<Integer> predicate,Integer integer){return predicate.test(integer);}
3.6 总结
- Supplier接口的方法一般用于
获得数据
- Consumer接口的方法 一般用于
处理数据
- Function接口的方法一般用于
转换数据
- Predicate接口的方法一般用于
判断数据
思维导图
最后
如果感觉有收获的话,点个赞 👍🏻 吧。
❤️❤️❤️本人菜鸟修行期,如有错误,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍