JDK1.8之Lambda表达式

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/wzj_110/article/details/80201470

一、 lambada表达式简介

      我们知道对于Java变量可以赋给其一个值,而如果想将"一块代码(一个完整的方法)"赋给一个Java变量,如下所示,怎么做呢?

      你可能认为就是下面的方式来实现


    很显然,这个并不是一个很简洁的写法,我们采用Java8的Lambada表达式来实现,那么如何简化呢

    整个过程:去掉修饰符(public等)、去掉函数的名字(因为已经赋给变量,变量知道此方法名--往后知道抽象方法唯一,不需要

方法名了)、去掉返回值类型(编译器可以推断)、去掉参数类型(编译器可以推断参数类型),最终的结果是下面的形式:


分析:这样的最终结果就是把"一块代码赋给一个变量"。或者说是"这个被赋给一个变量的函数"就是一个Lambada表达式,由于

Lambada可以直接赋给一个"变量",我们可以把Lambada(这里表示为变量)作为参数传递给函数

但是变量(Lambada表达式)的类型是什么呢?


说明:所有的Lambada的类型都是一个接口,而Lambada表达式本身("那段代码")就是一个接口的实现,这是理解Lambada的

一个关键所在,理解上可以这样认为:Lambada表达式就是产生一个实现接口中唯一的抽象方法的子实现类的对象,因此最终结

果:


函数式接口:接口中只有一个需要被实现的抽象函数

说明:为了避免后来的人在接口中增加新的接口函数,导致其有多个接口函数需要被实现,变成非函数式接口,引入了一个新的Annotation(注解):@FunctionalInterface。可以把他它放在一个接口前,表示这个接口是一个函数式接口,加上它的接口不会被编译,如果加上此标记就不能再添加其他的抽象方法,否则会报错。它有点像@Override,都是声明了一种使用意图,避免你把它用错。

总结:lambda表达式本质是匿名方法

二、 Lambda 表达式的结构

2.1 Lambada表达式的语法

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “ ->”,该操作符被称为 Lambda 操作符或

箭头操作符。它将 Lambda 分为两个部分:

即:(参数列表)—>{express或statements}

左侧: 指定了 Lambda 表达式需要的方法参数列表←→右侧: 指定了 Lambda 体,即 Lambda 表达式要执行的功能

2.2 使用说明

(1)一个 Lambda 表达式可以有零个或多个参数,参数的类型既可以明确声明,也可以根据上下文来推断

(2)圆括号内,方法参数列表之间用逗号相隔

(3)当只有一个参数,且其类型可推导时,圆括号()可省略

(4)Lambda 表达式的主体可包含零条或多条语句,如果 Lambda 表达式的主体只有一条语句,花括号{}可省略,如果有返回值,return也可以省略,同时body中的“;”也可以省略。匿名函数的返回类型与该主体表达式一致

(5)如果 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空

三、简单应用

(1)对比匿名内部类做为参数传递和Lambda表达式作为参数来传递--Runnable,Callable接口(具体看例子)

        匿名内部类作为参数传递和Lamada表达式作为参数传递

例1:


   
   
  1. package org.lamada;
  2. public class LamadaDemo0 {
  3. public static void main(String[] args) {
  4. //匿名内部类的形式开启一个线程
  5. new Thread( new Runnable() {
  6. @Override
  7. public void run() {
  8. System.out.println( "我爱你!");
  9. }
  10. }).start();
  11. //Lambada表达式创建匿名内部类开启一个线程
  12. new Thread(() -> System.out.println( "-------------")).start();
  13. }
  14. }

例2


   
   
  1. package org.lamada;
  2. public class LamadaDemo1 {
  3. public static void main(String[] args) {
  4. //常见的函数式接口:Runnable、 Comparable--排序(是一个函数式接口吗?)
  5. Comparable<Integer> comparable= new Comparable<Integer>() {
  6. @Override
  7. public int compareTo(Integer o) {
  8. return 0;
  9. }
  10. };
  11. //Lambada表达式的方法
  12. Comparable<Integer> com=(a)->a;
  13. int i = com.compareTo( 3);
  14. System.out.println(i);
  15. }
  16. }

例3


   
   
  1. package org.lamada;
  2. import java.util.Comparator;
  3. import java.util.TreeSet;
  4. public class LamadaDemo2 {
  5. public static void main(String[] args) {
  6. //TreeSet排序新高度---Comparator本身有泛型
  7. TreeSet<Integer> tereeSet = new TreeSet<>( new Comparator<Integer>() {
  8. @Override
  9. public int compare(Integer a, Integer b) {
  10. return a + b;
  11. }
  12. });
  13. //Lambada表达式的形式
  14. new TreeSet<Integer>((a,b)->a-b);
  15. }
  16. }

例4 自定义一个函数式接口


   
   
  1. package org.lamada;
  2. @FunctionalInterface
  3. public interface MyFunctionalInterface <T> {
  4. void method(T s); //自定义函数式接口---注意其定义
  5. //用一个注解 @FunctionalInterface 去检测这个接口是不是一个函数式接口
  6. }

测试


   
   
  1. package org.lamada;
  2. public class LamadaDemo3 {
  3. public static void main(String[] args) {
  4. //首先自定义一个函数式接口:MyFunctionalInterface
  5. new MyFunctionalInterface<String>() {
  6. @Override
  7. public void method(String s) {
  8. }
  9. }.method( "你好吗?");
  10. //Lamada表达式的用法
  11. MyFunctionalInterface<String> lamada=(s)-> System.out.println(s);
  12. }
  13. }

(3)Lambda 需要函数式接口的支持,来看下我们Java1.7以前遇到的函数式接口:点击打开链接

     在Java 8中有一个函数式接口的包,里面定义了大量可能用到的函数式接口(java.util.function)

(4)Java1.8中提供的一个新的一个接口函数包四大核心式接口

详见:点击打开链接,注意几个名词(消费型、供给型、函数型、断言型函数)

例5 使用function包中的函数式接口


   
   
  1. package org.lamada;
  2. import java.util.function.Supplier;
  3. public class LamadaDemo4 {
  4. public static void main(String[] args) {
  5. new Supplier<Double>() {
  6. @Override
  7. public Double get() {
  8. return 3.1;
  9. }
  10. };
  11. }
  12. }

四、方法引用

概念:方法引用其实是Lambda表达式的另一种写法,当要传递给Lambda体的操作已经有实现的方法了,可以使用方法引用。

语法:使用操作符 “ ::” 将方法名和对象或类的名字分隔开来

几种常见形式:

        (1)类名::静态方法
        (2)对象::实例方法

        (3)类名::实例方法

注意:
 *  1. Lambda体调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保存一致

 * 2.若Lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method;不管怎么说,实质还是抽象方法的实现

对比:相比而言省略参数列表,是因为二者的类型一致,主要凸显方法(重重之重!!)

应用:


   
   
  1. package com.company;
  2. import java.io.PrintStream;
  3. import java.util.Comparator;
  4. import java.util.function.BiFunction;
  5. import java.util.function.Consumer;
  6. import java.util.function.Function;
  7. import java.util.function.Supplier;
  8. public class LambdaDemo6 {
  9. public static void main(String[] args) {
  10. // 方法引用 :: 是Lambda表达式的另一种简写方式
  11. //类名::静态方法
  12. //对象::实例方法
  13. //类名::实例方法
  14. Supplier<Double> supplier = new Supplier<Double>() {
  15. @Override
  16. public Double get() {
  17. return Math.random();
  18. }
  19. };
  20. Supplier<Double> supplier2=()->Math.random(); //方法引用
  21. Supplier<Double> supplier3=Math::random;
  22. System.out.println( "-------------------------------------");
  23. Consumer<String> consumer = new Consumer<String>() {
  24. @Override
  25. public void accept(String s) {
  26. PrintStream out = System.out;
  27. out.println(s);
  28. }
  29. };
  30. PrintStream out = System.out;
  31. Consumer<String> consumer2=(s)->out.println(s);
  32. Consumer<String> consumer3=out::println; //方法引用也没有参数
  33. consumer3.accept( "bbbb");
  34. System.out.println( "------------------------------");
  35. Comparator<String> stringComparator = new Comparator<String>(){
  36. @Override
  37. public int compare(String s1, String s2) {
  38. //你对一个函数式接口中的抽象方法重写时,如果说你传的这两个参数
  39. //一个参数作为了调用者,一个参数作为了 传入者
  40. //那么你也可以使用方法引用来简写Lambda表达式
  41. return s1.compareTo(s2);
  42. }
  43. };
  44. Comparator<String> stringComparator2=(s1,s2)->s1.compareTo(s2);
  45. Comparator<String> stringComparator3=String::compareTo;
  46. System.out.println( "------------------------------------------------");
  47. Comparator<Integer> comparator = new Comparator<Integer>() {
  48. @Override
  49. public int compare(Integer a, Integer b) {
  50. return a.compareTo(b);
  51. }
  52. };
  53. Comparator<Integer> comparator2=(x,y)->x.compareTo(y);
  54. Comparator<Integer> comparator3=Integer::compareTo;
  55. }
  56. }

六、构造器引用----创建对象的专属

概念和应用

概念:与函数式接口相结合,自动与函数式接口中方法兼容。可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口

中抽象方法的参数列表一致!

细节问题:并没有说返回值类型,因此与返回值类型没有半毛钱关系,是对象创建简化的的福音

格式:ClassName:: new

注意:需要调用的构造器方法与函数式接口中抽象方法的参数列表保持一致

应用:自定义一个标记接口MyInterface,返回值类型为自定义类MyClass

MyInterface接口


   
   
  1. package org.lamada;
  2. @FunctionalInterface
  3. public interface MyInterface<T,R> {
  4. R method(T t); //有参---可以使用Java8中已经存在的Function---具备此特性
  5. }

MyClass类


   
   
  1. package org.lamada;
  2. public class MyClass {
  3. String s= null;
  4. public MyClass(String s) {
  5. //有参的构造方法--无参的更简单
  6. this.s=s;
  7. }
  8. }

测试类


   
   
  1. package org.lamada;
  2. public class LamadaDemo5 {
  3. public static void main(String[] args) {
  4. //(1)传统的方式
  5. MyInterface<String,MyClass> myInterface1 = new MyInterface<String,MyClass>() {
  6. @Override
  7. public MyClass method(String s) {
  8. return new MyClass(s);
  9. }
  10. };
  11. //(2)Lamada方式---首先实现此方法
  12. MyInterface<String,MyClass> myInterface2=(s)-> new MyClass(s);
  13. //(3)构造器引用的方式---不管参数了列表了,简化方法体
  14. MyInterface<String,MyClass> myInterface3=MyClass:: new;
  15. MyClass myclass = myInterface3.method( "你好吗?");
  16. System.out.println(myclass.s);
  17. //不管哪种方法,调用时传实参的形式是一致的
  18. }
  19. }

相关链接:点击打开链接点击打开链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值