【基础】Lambda表达式的入门与进阶

Lambda 表达式





初识 Lambda


  • 什么是 Lambda 表达式?

    • 自 Java 8 增加的新特性
    • 一个匿名方法(一个没有名字的方法,在定义变量的时候定义的方法)
  • 为什么使用 Lambda

    • 简洁实现接口对接;

    • 虽然可以使用 Lambda 表达式对某些接口进行实现,但是并不是所有的接口都可以使用 Lambda 来实现;

    • **实现要求:**要实现的抽象方法只能是一个;

    • 在 Java 8 中对接口实现了一个新特性 default ,被此方法修饰的方法在类中有一个默认实现,所以不影响使用 Lambda 的实现;

  • @FunctionalInterface

    • 一个用来修饰函数式接口的,接口中的抽象方法只能有一个;

    • // 错误代码展示
      @FunctionalInterface
      interface Comparer{
          int compare(int a,int b);// 方法一
          int show(int a,int b);	 // 方法二
      }
      

      ↑ ↑ ↑ 错误代码展示 ↑ ↑ ↑

    • 什么是函数式接口?

  • 代码示例

public class DEMO{
   public static void main(String[] args){
       // 方法一:使用接口实现类
       Comparator comparator = new MyComparator();
       
       //方法二:使用匿名内部类
       Comparator comparator = new Comparator(){
           @Override
           public int compare(int a,int b){
               return a-b;
           }
       }
       
       //方法三:使用Lambda表达式
       Comparator comparator2 = (a,b) -> a-b;
   }
}

// 一个接口
interface Comparator{
   int compare(int a,int b);
}

//方法一:使用实现类实现接口
class MyComparator implements Comparator{
   @Override
   public int compare(int a,int b){
       return a-b;
   }
}




Lambda 基础语法


  • 基础语法:

    • Lambda 是一个匿名函数
    • 包含:参数列表、方法体、(不包含:返回值类型、方法名)
  • 元素:

    • ():用来描述参数列表
    • {}:用来描述方法体
    • ->:分隔 Lambda 运算法,读作:goes to
  • 几种情况:

1、无参 无返回

// 无参 无返回
LambdaTest lam1 = ()->{
 Sout("Hello World!");
}
lam1.test();
// 结果:输出`Hello World!`

2、单个参 无返回

// 无参 单个返回值
LambdaTest lam2 = (int a)->{
 Sout(a);
}
lam2.test(10);
// 结果:输出`10`

3、多个参 无返回

LambdaTest lam3 = (int a,int b)->{
 Sout(a+b);
}
lam3.test(10,11);
// 结果:输出`21`

4、无参 有返回

LambdaTest lam4 = ()->{
 Sout(100);
 return 100;
}
int ret = lam4.test();
// 结果:输出`100` ; 返回 `100`

5、有参数 有返回

LambdaTest lam5 = (int a)->{
 Sout(a*2);
 return a*2;
}
int ret = lam5.test(10);
// 结果:输出`20` ; 返回 `20`

↑ ↑ ↑ 要注意 一定要定义相应的 函数式接口 ↑ ↑ ↑





Lambda 语法精简


  • 错误代码演示:
interface Lamx{
    int test(int a,int b);
}

Lamx lamx = (int a,int b)->{
    Sout("a=" + a + "\nb=" + b);
    // return a+b;
}

上面报错了?Lambda表达式如何知道有返回值?

Lambda 因为定义的接口有了说明,比如接口中写int test(int a);第一个int表示返回值类型,第二个int表示参数类型,所以 舍去了 return 就会报错;

既然在定义接口的时候已经定义了类型,那么是不是可以在写入参数的时候,将参数类型描述给省略掉呢?

  • 精简1:省略参数描述int

    代码演示:

interface Lamx{
    int test(int a,int b);
}

Lamx lamx = (a,b)->{
    Sout("a=" + a + "\nb=" + b);
    return a+b;
}

接口中已经说明了有int类型的返回值,所以不写return是错误的;

两个必须同时省略,不能一个写一个不写;

  • 精简2:省略小括号()

    代码演示:

interface Lamx{
    int test(int a);
}

Lamx lamx = a -> {
    Sout("a=" + a );
    return a;
}

当 入参 只有一个的时候,可以省略入参的 括号;

  • 精简3:省略大括号{}
interface Lamx{
    int test(int a);
}

Lamx lamx = a -> Sout( a );

当 函数 只有一行的时候,可以省略大括号;

  • 精简4:省略return
interface Lamx{
    int test(int a);
}

Lamx lamx = a -> a;

如果唯一一条语句是return语句,那么省略大括号的同时,也必须省略return

Lamx lamx = (a,b)->a+b;
lamx.test(5,10);




Lambda 语法进阶


  • Lambda 调用静态方法
    • 代码示例:
public class Test{
    public static void main(String[] args){
        // 实现方式一: 传统 Lambda 语法
        Lamx lamx = a -> change(a);
        // 实现方式二: 双" : "语法
        Lamx lamx = Test::change;
    }
    
    public static int change(int a){
        return a*2;
    }
}

将 Lambda 指向一个已经实现的方法;语法规则 – 方法隶属者::方法名

此处的change是一个静态方法,隶属者就是Test类,所以就是Test::change

  • 注意事项:
    • 参数的数量和类型一定要和方法中定义的一致
    • 返回型一定要和接口中定义的方法一致

  • Lambda 调用构造方法
    • 保留
// 构造方法
public class Person{
    public String name;
    public int age;
    
    public Person(){
        Sout("Person类的 无参 构造方法执行了;");
    }
    
    public Person(String name,int age){
        this.name = name;
        this.age  = age;
        Sout("Person类的 有参 构造方法执行了;");
    }
}
// Lambda 语法
public class Lamx{
    public static void main(String[] args){
        // 原始方法
        PersonCreater creater1 = () -> {
            return new Person();
        };
        
        // 简化方法
        PersonCreater creater2 = () -> new Person();
        
        // 构造方法的引用
        PersonCreater creater3 = Person::new;
        Person a = creater3.getPersonNull();
        Person a = creater3.getPersonDouble("张三",18);
    }
}

//接口中要说明 返回值类型 方法参数!!!
interface PersonCreater{
    Person gerPersonNull();
    Person getPersonDouble(String name,int age);
}

实现语法 – 类::new





Lambda 实现实例


1、已知在一个 ArrayList 类中有若干个 Person 对象,讲这些Person对象按照年龄进行降序排序;

public class Exercise{
    public static void main(String[] args){
        ArrayList<Person> list = new ArrayList<>();
        list.add(new Person("张三",12));
        list.add(new Person("李四",13));
        list.add(new Person("韩梅梅",16));
        list.add(new Person("赵四",6));
        list.add(new Person("尼古拉斯凯奇",46));
        list.add(new Person("Tony",54));
        
        list.sort((o1,o2)-> o2.age-o1.age);
    }
}

2、使用TreeSet排序

TreeSer<Person> set = new TreeSer<>((o1,o2)->o2.age-01.age);
set.add(new Person("xiaoming",10));
set.add(new Person("wanggang",11));
set.add(new Person("zhaosi",8));
set.add(new Person("Nigu",43));
set.add(new Person("Tony",22));
set.add(new Person("poily",8));
set.add(new Person("Wngffei",40));
Sout(set);
//运行结果:基本正确,但是只有一个8岁的人;

代码优化

TreeSer<Person> set = new TreeSer<>((o1,o2)->{
    if(o1.age >= o2.age){
        retrun -1;
    }else{
        return 1;
    }
});
set.add(new Person("xiaoming",10));
set.add(new Person("wanggang",11));
set.add(new Person("zhaosi",8));
set.add(new Person("Nigu",43));
set.add(new Person("Tony",22));
set.add(new Person("poily",8));
set.add(new Person("Wngffei",40));
Sout(set);
//运行结果:正确;

public static void main(String[] args){
    ArrayList<Interger> list -= new ArrayList<>();
    Collection.addAll(list,1,2,3,4,5,6,7,8,9,0);
    list.forEach(ele->{
        if(ele%2 == 0)
            Sout(ele);
    });
}




使用 Lambda 实现线程的实例化

实现线程的实例化;


public static void main(String[] args){
    Thread t = new Thread(()->{
        for(int i=0;i<100;i++){
            Sout(i);
        }
    });
    t.start();
}




系统内置的函数式接口


public static void (String[] args){//最常用的是Predicate、Consumer、Function、Supplier
    
    // Predicate		:	参数T ·返回值 boolean
    //	IntPredicate	:	int-> boolean
    //	LongPredicate	:	long->boolean
    //	DoublePredicate	:	double
    
    // Consumer		:	参数T ·返回值 void
    // 	IntConsumer		:	int ->void
    // 	LongConsumer
    // 	DoubleConsumer
    
    // Function	:	参数T ·返回值 R
    //	IntFuncation	:	int->R
    //	LongFunction
    //	DoubleFunction
    //	IntToLongFunction:	int->long
    //	IntToDoubleFunction
    //	LongToIntFunction
    //	LongToDoubleFunction
    //	DoubleToIntFunction
    //	DoubleToLongFunction
    
    // Supplier		:	参数无 ·返回值 T
 	//	……省略好多好多   
    // UnaryOperator	:	参数T	 ·返回值T
    // BinaryOperator	:	参数T,T ·返回值T
    // BiFunction:	参数T,U ·返回值R
    // BiPredicate	:	参数T,U ·返回值boolean
    // BiConsumer	:	参数T,U ·返回值void
}




闭包问题


  • 什么是闭包
    • 闭包会提升变量的生命周期,这样就可以获取某一个方法中的局部变量
public static void main(String[] args){
    int n = getNum().get();
    Sout(n);
    //结果是10;
}

private static Supplier<Integer> getNum(){
    int num = 10;
    
    return ()->{
        return num;
    };
}

代码二:

PSVM(String[] args){//public static void main
    int a = 10;
    
    Consumer<Integer> c = ele->{
        Sout(a+1);
    };
    
    c.accept(1);// 结果11
    
        Consumer<Integer> c = ele->{
        Sout(a++);
    };
    
    c.accept();// 结果报错,因为 闭包 中的变量必须是 final 的(也就是一个常量),所以不能修改这个值
}

你可能感兴趣的:(Java,lambda,java)