JDK1.8新特性(部分)【Lambda表达式、函数式接口】--学习JavaEE的day41

day41

JDK1.8新特性

JDK1.8新特性简介

  • 速度更快 - 优化底层源码,比如HashMap、ConcurrentHashMap
  • 代码更少 - 添加新的语法Lambda表达式
  • 强大的Stream API
  • 便于并行
  • 最大化减少空指针异常 - Optional

Lambda表达式

简介

Lambda是一个匿名函数(方法), 允许把函数作为一个方法的参数 。利用Lambda表达式可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

一般都是优化匿名内部类

基础语法

无参数、无返回值的抽象方法

java 复制代码
public class Test1 {
	@Test
	public void test01() {
//		I1 i1 = new I1() {
//			@Override
//			public void method() {
//				System.out.println("传统使用匿名内部类的方式");
//			}
//		};
//		i1.method();

//		I1 i1 = ()->{
//			System.out.println("使用lambda表达式的方式");
//		};
//		i1.method();
        
        //lambda表达式里面只有一个语句情况,大括号可以省略进行简化代码
		I1 i1 = ()-> System.out.println("采用Lambda表达式的方式");
		i1.method();
	}
}
interface I1{
	public void method();//无参数、无返回值的抽象方法
}

一个参数、无返回值的抽象方法

外部new匿名内部类调用方法时,参数看接口定义的规范里的参数类型

java 复制代码
public class Test01 {
	public static void main(String[] args) {
		
//		I1 i1 = new I1() {
//			@Override
//			public void method(String str) {
//				System.out.println("使用传统匿名内部类的方式:" + str);
//			}
//		};
//		i1.method("过往云烟");
		
//		I1 i1 = (String str)->{
//			System.out.println("使用lambda表达式的方式:" + str);
//		};
//		i1.method("过往云烟");
		
//		I1 i1 = (String str)->System.out.println("使用lambda表达式的方式:" + str);
//		i1.method("过往云烟");
		
		
//		I1 i1 = (str)->System.out.println("使用lambda表达式的方式:" + str);
//		i1.method("过往云烟");
		
		I1 i1 = str->System.out.println("使用lambda表达式的方式:" + str);
		i1.method("过往云烟");
	}
}
public interface I1 {

	public void method(String str);//一个参数、无返回值的抽象方法
}

多个参数、无返回值的抽象方法

java 复制代码
public class Test01 {
	public static void main(String[] args) {
		
//		I1 i1 = new I1() {
//			@Override
//			public void method(String str, int i) {
//				System.out.println("使用传统匿名内部类的方式:" + str + " -- " + i);
//			}
//		};
//		i1.method("过往云烟", 666);
		
//		I1 i1 = (String str,int i)->{
//			System.out.println("使用lambda表达式的方式:" + str + " -- " + i);
//		};
//		i1.method("过往云烟", 777);
		
//		I1 i1 = (String str,int i)->System.out.println("使用lambda表达式的方式:" + str + " -- " + i);
//		i1.method("过往云烟", 888);
		
		I1 i1 = (str, i)->System.out.println("使用lambda表达式的方式:" + str + " -- " + i);
		i1.method("过往云烟", 999);
		
	}
}
public interface I1 {
    //多个参数、无返回值的抽象方法
	public void method(String str,int i);
}

多个参数、有返回值的抽象方法

java 复制代码
public class Test01 {
	public static void main(String[] args) {
	
//		I1 i1 = new I1() {
//			@Override
//			public String method(int a, int b) {
//				return "使用传统匿名内部类的方式:" + (a+b);
//			}
//		};
//		String method = i1.method(10, 10);
//		System.out.println(method);
		
//		I1 i1 = (int a,int b)->{
//			return "使用lambda表达式的方式:" + (a+b);
//		};
//		String method = i1.method(20, 20);
//		System.out.println(method);
		
		I1 i1 = (a, b)-> "使用lambda表达式的方式:" + (a+b);
		String method = i1.method(30, 30);
		System.out.println(method);
		
	}
}
public interface I1 {
	//多个参数、有返回值的抽象方法
	public String method(int a,int b);
}
注意点
  1. 重写方法的形参只有一个时,可以不加小括号
  2. Lambda表达式当中不允许声明一个与局部变量同名的参数或者局部变量
  3. Lambda表达式中访问外层的局部变量,外层的局部变量自动变成隐式常量,默认添加final
  4. 重写方法的形参同时加类型或同时不加类型
java 复制代码
public class Test1 {
	@Test
	public void test01() {
		int x;
		int num = 10;
		I1 i1 = x -> System.out.println(x + (num++));
        i1.method(1000);
		
		I2 i2 = (int x,int y) -> {
			int result = x+y;
			return result;
		};
		int result = i2.method(10, 20);
		System.out.println(result);
	}
}
interface I1{
	public void method(int num1);
}
interface I2{
	public int method(int num1,int num2);
}
案例
案例1

1.调用Collections.sort()方法,通过定制排序比较两个Student对象(先按年龄比较,年龄相同按照薪资比较),使用Lambda表达式作为参数传递
注意:比较时注意不能用减,因为doublue减后的小数会在转int损失精度,ps:0.2变为0

java 复制代码
public class Test01 {

	public static void main(String[] args) {
		
		List<Student> stuList = Arrays.asList(
				new Student("张三", 28, 4800,Course.JAVA),
				new Student("李四", 36, 7200,Course.JAVA),
				new Student("王五", 19, 9600,Course.HTML),
				new Student("赵六", 42, 6100,Course.HTML),
				new Student("孙七", 23, 9600,Course.PYTHON),
				new Student("吴八", 28, 3000,Course.PYTHON));
		
//		Collections.sort(stuList, new Comparator<Student>() {
//			@Override
//			public int compare(Student o1, Student o2) {
//				if(o1.equals(o2)){
//					return 0;
//				}
//				
//				int compare = Integer.compare(o1.getAge(), o2.getAge());
//				if(compare != 0){
//					return compare;
//				}
//				
//				return Double.compare(o1.getSalary(), o2.getSalary());
//			}
//		});
		
		Collections.sort(stuList, (o1,o2)->{
			if(o1.equals(o2)){
				return 0;
			}
			
			int compare = Integer.compare(o1.getAge(), o2.getAge());
			if(compare != 0){
				return compare;
			}
			
			return Double.compare(o1.getSalary(), o2.getSalary());
		});
		
		for (Student stu : stuList) {
			System.out.println(stu);
		}
		
	}
}
public enum Course{//课程枚举
	JAVA,HTML,PYTHON;
}
public class Student{//学生类
	
	private String name;
	private int age;
	private double salary;
	private Course course;
    //有参、无参、get、set方法【略】
@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((course == null) ? 0 : course.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		long temp;
		temp = Double.doubleToLongBits(salary);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (age != other.age)
			return false;
		if (course != other.course)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
			return false;
		return true;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Student [name=");
		builder.append(name);
		builder.append(", age=");
		builder.append(age);
		builder.append(", salary=");
		builder.append(salary);
		builder.append(", course=");
		builder.append(course);
		builder.append("]");
		return builder.toString();
	}

}
案例2

2.创建I1接口,创建抽象方法:public String getValue(String str),在测试类中编写方法使用接口作为参数,将一个字符串转为大写,并作为方法的返回值

java 复制代码
public class Test01 {
    
	public static void main(String[] args) {
		
		String str = method("abc", (x)-> {
			return x.toUpperCase();
		});
		System.out.println(str);
		
		
	}
	
	public static String method(String str,I1 i1){
		return i1.getValue(str);
	}
}

interface I1{
	public String getValue(String str);
}
案例3

3.创建I1<T,R>接口,泛型T为参数,R为返回值,创建抽象方法:public R add(T t1,T t2),在测试类中编写方法使用接口作为参数,计算两个long类型的和

java 复制代码
public class Test01 {

	public static void main(String[] args) {
		
		long addLong = addLong(100,200,(a,b)->{
			return a+b;
		});
		System.out.println(addLong);
		
		
	}
	
	public static long addLong(long l1,long l2,I1<Long,Long> i1){
		return i1.add(l1, l2);
	}
}
interface I1<T,R>{
	public R add(T t1,T t2);
}

函数式接口

简介

函数式接口是指仅仅只包含一个抽象方法的接口,jdk1.8提供了一个@FunctionalInterface注解来定义函数式接口,如果我们定义的接口不符合函数式的规范便会报错。配合Lambda表达式一起使用

四大核心函数式接口
函数式接口 参数类型 返回类型 用途
Consumer 消费型接口 T void void accept(T t);
Supplier 供给型接口 void T T get();
Function<T, R> 函数型接口 T R R apply(T t);
Predicate 断言型接口 T boolean booelan test(T t);
BiConsumer<T, U> T,U void 对类型为T,U参数应用操作。包含方法为void accept(T t,U u);
BiFunction<T, U, R> T,U R 对类型为T,U参数应用操作,并返回R类型的结果。包含方法为R apply(T t,U u);
UnaryOperator extends Function<T, T> T T 对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为T apply(T t);
BinaryOperator extends BiFunction<T,T,T> T,T T 对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为T apply(T t1,T t2);
ToIntFunction ToLongFunction ToDoubleFunction T int long double 分别计算int、long、double值的函数
IntFunction LongFunction DoubleFunction int long double R 参数为int、long、double类型的函数

应用场景:当项目中需要一个接口,并且该接口中只有一个抽象方法,就没必要去创建新的接口,直接选择Java提供的使用合适的函数式接口即可

案例替换

对Lambda表达式案例,使用合适的函数式接口去替换I1
创建I1接口,创建抽象方法:public String getValue(String str),

在测试类中编写方法使用接口作为参数,将一个字符串转为大写,并作为方法的返回值

注意:使用合适的函数式接口去替换I1

函数和方法:前端习惯称函数,后端习惯称方法,简单理解一个意思但非区别

函数式接口,一个抽象方法,超过就会报错

函数式接口替换接口,就案例来看更改方法里的接口,用函数调用方法,少一层

java 复制代码
public class Test01 {

	public static void main(String[] args) {
		
		String str = method("abc", (x)->{
			return x.toUpperCase();
		});
		System.out.println(str);
		
		
	}
	
	public static String method(String str,Function<String, String> fun){
		return fun.apply(str);
	}
}
public class Test02 {

	public static void main(String[] args) {
		
		String str = method("abc", (x)->{
			return x.toUpperCase();
		});
		System.out.println(str);
		
		
	}
	
	public static String method(String str,UnaryOperator<String> uo){
		return uo.apply(str);
	}
}

创建I1<T,R>接口,泛型T为参数,R为返回值,创建抽象方法:public R add(T t1,T t2),

在测试类中编写方法使用接口作为参数,计算两个long类型的和

java 复制代码
public class Test01 {

	public static void main(String[] args) {
		
		long addLong = addLong(100,200,(a,b)->{
			return a+b;
		});
		System.out.println(addLong);
		
		
	}
	
	public static long addLong(long l1,long l2,BiFunction<Long, Long, Long> bf){
		return bf.apply(l1, l2);
	}
}
public class Test02 {
	public static void main(String[] args) {
		
		long addLong = addLong(100,200,(a,b)->{
			return a+b;
		});
		System.out.println(addLong);
		
		
	}
	
	public static long addLong(long l1,long l2,BinaryOperator<Long> bo){
		return bo.apply(l1, l2);
	}
}

总结

1.lambda表达式(其实就有优化匿名内部类的方案)

注意:使用lambda表达式必须有多态的思想

2.函数式接口

该接口中只有一个抽象方法

@FunctionInterface这个注解表示该接口是函数式接口

经验:

如果你想玩转lambda表达式,必须先去学习匿名内部类+多态

函数式接口应用场景:需求要你写个接口,这个接口只有一个抽象方法,就用函数式接口去代替

相关推荐
用户37215742613522 分钟前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊1 小时前
Java学习第22天 - 云原生与容器化
java
渣哥3 小时前
原来 Java 里线程安全集合有这么多种
java
间彧3 小时前
Spring Boot集成Spring Security完整指南
java
间彧4 小时前
Spring Secutiy基本原理及工作流程
java
Java水解5 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆7 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学7 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole7 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端
华仔啊7 小时前
基于 RuoYi-Vue 轻松实现单用户登录功能,亲测有效
java·vue.js·后端