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


    day41

    JDK1.8新特性

    JDK1.8新特性简介

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

    Lambda表达式

    简介

    Lambda是一个匿名函数(方法), 允许把函数作为一个方法的参数 。利用Lambda表达式可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使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();//无参数、无返回值的抽象方法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

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

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

    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);//一个参数、无返回值的抽象方法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

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

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

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

    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
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    注意点
    1. 重写方法的形参只有一个时,可以不加小括号
    2. Lambda表达式当中不允许声明一个与局部变量同名的参数或者局部变量
    3. Lambda表达式中访问外层的局部变量,外层的局部变量自动变成隐式常量,默认添加final
    4. 重写方法的形参同时加类型或同时不加类型
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    案例
    案例1

    1.调用Collections.sort()方法,通过定制排序比较两个Student对象(先按年龄比较,年龄相同按照薪资比较),使用Lambda表达式作为参数传递

    注意:比较时注意不能用减,因为doublue减后的小数会在转int损失精度,ps:0.2变为0

    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() {
    //			@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();
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    案例2

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

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    案例3

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

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    函数式接口

    简介

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

    四大核心函数式接口
    函数式接口参数类型返回类型用途
    Consumer 消费型接口Tvoidvoid accept(T t);
    Supplier 供给型接口voidTT get();
    Function 函数型接口TRR apply(T t);
    Predicate 断言型接口Tbooleanbooelan test(T t);
    BiConsumerT,Uvoid对类型为T,U参数应用操作。包含方法为void accept(T t,U u);
    BiFunctionT,UR对类型为T,U参数应用操作,并返回R类型的结果。包含方法为R apply(T t,U u);
    UnaryOperator extends FunctionTT对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为T apply(T t);
    BinaryOperator extends BiFunctionT,TT对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为T apply(T t1,T t2);
    ToIntFunction ToLongFunction ToDoubleFunctionTint long double分别计算int、long、double值的函数
    IntFunction LongFunction DoubleFunctionint long doubleR参数为int、long、double类型的函数

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

    案例替换

    对Lambda表达式案例,使用合适的函数式接口去替换I1

    创建I1接口,创建抽象方法:public String getValue(String str),

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

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

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

    函数式接口,一个抽象方法,超过就会报错
    函数式接口替换接口,就案例来看更改方法里的接口,用函数调用方法,少一层

    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);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

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

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

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    总结

    1.lambda表达式(其实就有优化匿名内部类的方案)
    注意:使用lambda表达式必须有多态的思想

    2.函数式接口
    该接口中只有一个抽象方法
    @FunctionInterface这个注解表示该接口是函数式接口

    经验:
    如果你想玩转lambda表达式,必须先去学习匿名内部类+多态
    函数式接口应用场景:需求要你写个接口,这个接口只有一个抽象方法,就用函数式接口去代替

  • 相关阅读:
    基于KPCA 和 STFT 非侵入式负荷监控(Matlab代码实现)
    go中的方法 func-----数据类型
    【Leetcode】1210. Minimum Moves to Reach Target with Rotations
    宏转录组分析揭示不同土壤生境中氮循环基因的表达
    大数据采集技术有哪些
    Feign 调用出现异常:feign.FeignException: status 401 reading xxx#xxx(xxx)
    Websocket、Session&Cookie、前端基础知识
    Win11系统启动文件夹是空的怎么解决?
    单片机测量任务运行时间
    【云原生】Secret敏感信息存储
  • 原文地址:https://blog.csdn.net/gangain/article/details/138162857