java进阶打卡34

函数式接口

函数式接口:有且只有一个抽象方法的接口,称之为函数式接口。当然接口中可以包含其他的方法(默认,静态,私有)。

函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。
只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。

备注:“语法糖”是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实底层的实现原理仍然是迭代器,这便是“语法糖”。
从应用层面来讲,Java中的Lambda可以被当做是匿名内部类的“语法糖”,但是二者在原理上是不同的。

@FunctionalInterface注解
作用:可以检测接口是否是一个函数式接口
    是:编译成功
    否:编译失败(接口中没有抽象方法、抽象方法的个数多于1个)

例如:
@FunctionalInterface
public interface MyFunctionalInterface {
    public abstract void method();
} 

【函数式接口的使用】:一般可以作为方法的参数和返回值类型
// 定义一个方法,参数使用函数式接口MyFunctionalInterface
public static void show(MyFunctionalInterface myInter){
	myInter.method();
}
public static void main(String[] args) {
	// 调用show方法,方法的参数是一个接口,所以可以传递接口的实现类对象
    show(new MyFunctionalInterfaceImpl());

    // 调用show方法,方法的参数是一个接口,所以我们可以传递接口的匿名内部类
    show(new MyFunctionalInterface() {
		@Override
        public void method() {
        	System.out.println("使用Lambda表达式重新接口中的抽象方法");
        }
	});

    // 调用show方法,方法的参数是一个函数式接口,所以我们可以使用Lambda表达式
    show(()->{
		System.out.println("使用Lambda表达式重写接口中的抽象方法");
    });

	// 简化Lambda表达式
	show(()->System.out.println("使用Lambda表达式重写接口中的抽象方法"));
}   

性能浪费的日志案例

日志可以帮助我们快速的定位问题,记录程序运行过程中的情况,以便项目的监控和优化。

public static void showLog(int level, String message){
	// 对日志的等级进行判断,如果是1级别,那么输出日志信息
    if(level == 1){
		System.out.println(message);
    }
}
public static void main(String[] args){
	// 定义三个日志信息
    String msg1 = "Hello";
    String msg2 = "World";
    String msg3 = "Java";

	// 调用showLog方法,传递日志级别和日志信息
    showLog(1,msg1 + msg2 + msg3);
}

注意:
发现代码存在一些性能浪费的问题。调用showLog方法,传递的第二个参数是一个拼接后的字符串。先把字符串拼接好,然后再调用showLog方法。
showLog方法中如果传递的日志等级不是1级,那么就不会输出拼接后的字符串。所以感觉字符串就白拼接了,存在了浪费。

使用Lambda优化日志案例

Lambda的特点:延迟加载
Lambda的使用前提,必须存在函数式接口

@FunctionalInterface
public interface MessageBuilder {
	// 定义一个拼接消息的抽象方法,返回被拼接的消息
    public abstract String builderMessage();
}

public static void showLog(int level, MessageBuilder mb){
	// 对日志的等级进行判断,如果是1级,则调用MessageBuilder接口中的builderMessage方法
    if(level == 1){
    	System.out.println(mb.builderMessage());
    }
}

public static void main(String[] args) {
	String msg1 = "Hello";
	String msg2 = "World";
	String msg3 = "Java";

	// 调用showLog方法,参数MessageBuilder是一个函数式接口,所以可以传递Lambda表达式
	showLog(1,()->{
		// 返回一个拼接好的字符串
        return msg1 + msg2 + msg3;
	});
}

注意:
使用Lambda表达式作为参数传递,仅仅是把参数传递到showLog方法中。
只有满足条件,日志的等级是1级。才会调用接口MessageBuilder中的方法builderMessage,才会进行字符串的拼接。
如果条件不满足,日志的等级不是1级。那么MessageBuilder接口中的方法builderMessage也不会执行,所以拼接字符串的代码也不会执行。不会存在性能的浪费。

函数式接口作为方法的参数案例

java.lang.Runnable接口就是一个函数式接口
假设有一个startThread方法使用该接口作为参数,那么就可以使用Lambda进行传参
这种情况其实和Thread类的构造方法参数为Runnable没有本质区别

// 定义一个方法startThread,方法的参数使用函数式接口Runnable
public static void startThread(Runnable run){
	// 开启多线程
    new Thread(run).start();
}

public static void main(String[] args){
	// 调用startThread方法,方法的参数是一个接口,那么我们可以传递这个接口的匿名内部类
	startThread(new Runnable() {
		@Override
    	public void run() {
    		System.out.println(Thread.currentThread().getName() + "-->" + "线程启动了");
    	}
	});

	// 调用startThread方法,方法的参数是一个函数式接口,所以可以传递Lambda表达式
    startThread(()->{
    	System.out.println(Thread.currentThread().getName() + "-->" + "线程启动了");
    });

	// 优化Lambda表达式
    startThread(()->System.out.println(Thread.currentThread().getName() + "-->" + "线程启动了"));
}

函数式接口作为方法的返回值类型案例

如果一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式
当需要通过一个方法来获取一个java.util.Comparator接口类型的对象作为排序器时,就可以调用该方法获取。

// 定义一个方法,方法的返回值类型使用函数式接口Comparator
public static Comparator<String> getComparator(){
	// 方法的返回值类型是一个接口,那么我们可以返回这个接口的匿名内部类
	/*return new Comparator<String>() {
		@Override
        public int compare(String o1, String o2) {
        	// 按照字符串的降序排序
       		return o2.length() - o1.length();
        }
	};*/

	// 方法的返回值类型是一个函数式接口,所以我们可以返回一个Lambda表达式
	/*return (String o1, String o2)->{
    	return o2.length() - o1.length();
    };*/

	// 继续优化Lambda表达式
    return (o1, o2)->o2.length() - o1.length();
}

public static void main(String[] args) {
	// 创建一个字符串数组
    String[] arr = {"aaa","b","cccccc","ddddddddddd"};
    // 输出排序前的数组
    System.out.println(Arrays.toString(arr)); // [aaa, b, cccccc, ddddddddddd]
    // 调用Arrays中的方法,对字符串数组进行排序
    Arrays.sort(arr,getComparator());
    // 输出排序后的数组
    System.out.println(Arrays.toString(arr)); // [ddddddddddd, cccccc, aaa, b]
}
Java员工打卡签到代码的实现方式有很多种,以下是其中一种可能的实现方式: ```java import java.util.Date; public class Employee { private String name; private Date lastSignIn; public Employee(String name) { this.name = name; } public void signIn() { Date now = new Date(); System.out.println(name + "签到成功,时间:" + now); lastSignIn = now; } public void signOut() { Date now = new Date(); System.out.println(name + "签退成功,时间:" + now); } public void checkInStatus() { if (lastSignIn == null) { System.out.println(name + "尚未签到"); } else { System.out.println(name + "上次签到时间:" + lastSignIn); } } } ``` 上面的代码定义了一个`Employee`类,其中包含了员工的姓名和上次签到时间。类中有三个方法:`signIn()`、`signOut()`和`checkInStatus()`。`signIn()`方法表示员工签到,会打印出员工姓名和当前时间,并将当前时间记录为上次签到时间;`signOut()`方法表示员工签退,会打印出员工姓名和当前时间;`checkInStatus()`方法表示查询员工的签到状态,会打印出员工姓名和上次签到时间(如果已经签到过),否则会提示尚未签到。 如果要使用这段代码,可以在其他类中创建`Employee`对象,并调用其中的方法来完成打卡签到功能。例如: ```java public class Main { public static void main(String[] args) { Employee emp1 = new Employee("张三"); emp1.signIn(); emp1.checkInStatus(); emp1.signOut(); } } ``` 这段代码创建了一个名为`emp1`的`Employee`对象,姓名为“张三”。接着调用了`signIn()`方法进行签到,`checkInStatus()`方法查询签到状态,最后调用了`signOut()`方法进行签退。运行这段代码后,会打印出以下结果: ``` 张三签到成功,时间:Thu Jul 22 14:47:23 CST 2021 张三上次签到时间:Thu Jul 22 14:47:23 CST 2021 张三签退成功,时间:Thu Jul 22 14:47:28 CST 2021 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值