目录
- 一、关于接口的新特性
- 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{
@Override
public void fun1() {
System.out.println("重写旧方法");
}
@Override
public 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( ) {
@Override
public 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接口的方法一般用于
判断数据
思维导图
最后
如果感觉有收获的话,点个赞 👍🏻 吧。
❤️❤️❤️本人菜鸟修行期,如有错误,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍