lambda表达式

[原文地址为]https://www.cnblogs.com/haixiang/p/11029639.html#791844013

定义

lambda表达式是jdk1.8后新增的特性,它可以取代大部分匿名内部类,简化Java代码结构。
lambda表达式是基于函数式接口使用的。
什么是函数式接口?
函数式接口是指只含有一个必须被重写的方法的接口。
(注:只有一个必须重写的方法,并不是指只有一个方法,jdk1.8后接口中允许有已经实现的方法(必须被public static修饰),jdk1.8后也允许有非必须重写的抽象方法(须被default修饰))

@FunctionalInterface

函数式接口又称为功能性接口,故一般函数式接口都用@FunctionalInterface注解进行修饰。
(不使用该注解,jvm虚拟机也可判断出该接口是一个函数式接口,但为了防止其他同事在该接口中新增方法,最好使用注解注明)

lambda基础语法

lambda基础语法一般是基于以下6种函数式接口

//1.无返回无参数函数式接口
@FunctionalInterface
public interface noReturnNOParam{
  void method();
}
//2.无返回一参数函数式接口
public interface noReturnOneParam{
  void method(int a);
}
//3.无返回多参数函数式接口
public interface noReturnMultiParam{
  void method(int a,int b);
}
//4.有返回无参数函数式接口
public interface ReturnNoParam{
  String method();
}
//5.有返回一参数函数式接口
public interface ReturnOneParam{
  String method(int a);
}
//6.有返回多参数函数式接口
public interface ReturnMultiParam{
  String method(int a,int b);
}

lambda表达式的基础语法为()->{},其中()中保存参数列表,->是lambda表达式的执行符,读作goes to,{}中保存方法体。
关于lambda表达式,这里有一句口诀:
上联:左右遇一括号省
下联:左边类推类型省
横批:能省则省
解释
左右遇一括号省
左指的是若只有一个参数,则左边参数的括号可省略不写。
右指的是若方法体中只有一条Java语句,则右边的括号也可省略不写。
左边类推类型省:
jvm虚拟机的类推机制,可通过方法体中的语句,联系上下文推测出参数列表的类型,因此左边的参数类型可省略不写。

针对上述接口及口诀,下方有几个例子

public class testLambda(){
  public static void main(String args[]){
  //1.无返回,无参数值
  noReturnNOParam emp1=()->{
      System.out.println("无返回无参数值");
    };
  emp1.method();//这里的method是上述函数式接口中定义的方法名
  //使用口诀简化版
  noReturnNoParam emp1=()-> System.out.println("无返回无参数值");
  emp1.method();
  //注意这边参数为0个,所以左边括号不能省 
  //============================================================
  //2.无返回,一参数值
  noReturnOneParam emp2=(String a)->{
    System.out.println("无返回,一参数值"+a);
  }; 
  emp2.method("11111");
  //简化版
  noReturnOneParam emp2=a->
  System.out.println("无返回,一参数值"+a);
  emp2.method("11111");
  //=============================================================
  //3.无返回,多参数值
  noReturnMultiParam emp3=(int a,int b)->{
    System.out.println("无返回,一参数值"+(a+b));
  };
  emp3.method(1,2);
  //简化版
  noReturnMultiParam emp3=(a,b)->System.out.println("无返回,多参数值"+(a+b));
  emp3.method(1,2);
  //======================================================================
  //4.有返回,无参数值
  ReturnNOParam emp4=()->{
      return "无返回无参数值";
    };
  String return1=emp4.method();//这里的method是上述函数式接口中定义的方法名
  //使用口诀简化版
  noReturnNoParam emp1=()->  return "无返回无参数值";
  String return1=emp4.method();
  //注意这边参数为0个,所以左边括号不能省 
  //============================================================
  //5.有返回,一参数值
  ReturnOneParam emp5=(String a)->{
    return "有返回,一参数值"+a;
  }; 
  String return2=emp5.method("11111");
  //简化版
  ReturnOneParam emp5=a->
  return "无返回,一参数值"+a;
  String return2=emp5.method("11111");
  //=============================================================
  //6.无返回,多参数值
  ReturnMultiParam emp6=(int a,int b)->{
    return "无返回,一参数值"+(a+b);
  };
  String return3=emp6.method(1,2);
  //简化版
  ReturnMultiParam emp6=(a,b)->return "无返回,多参数值"+(a+b);
  String return3=emp6.method(1,2);
 }
}

Lambda表达式常用方法示例

lambda表达式引用方法

可以利用lambda表达式的接口直接指向一个已经实现的方法
要求:
1.这个方法的参数类型及个数要与函数式接口中的方法一致
2.这个方法的返回值类型要与函数式接口中的方法一致
语法:
方法名::方法的归属者,静态方法的归属者为类名,普通方法的归属者为对象
举例:

public class lambdaUse1{
  public static void main(String args[]){
    ReturnMultiParam return1=fangfa1::lambdaUse1;
    return1.method(1,2);
  }
  public static String fangfa1(int a,int b){
    int c=a+b;
    return "lambda表达式的用法1"+c;
  }
}
//就相当于用引用的方法重写了原接口中的方法,就是lambda表达式中的goes to到引用方法的方法体中

构造方法的引用

若一个函数式接口中的方法,是一个类的构造方法,则可通过lambda表达式来创建该类的对象,
语法:类名::new

//无参构造
public Interface ItemCreaterConstruct(){
  Item getItem();
}
//含参构造
public Interface ItemParamCreaterConstruct(){
  Item getItem(int id,String name,double price);
}

public class emp(){
  public static void main(String args[]){
    //无参构造,使用lambda表达式创建对象
    ItemCreaterConstruct construct=()->new Item();
    Item item=construct.getItem();
    //无参构造,使用lambda表达式的另一种写法创建对象
    ItemCreaterConstruct construct=Item::new;
    Item item=construct.getItem();
    //含参构造,使用lambda表达式创建对象
    ItemCreaterConstruct construct=Item::new;
    Item item=construct.getItem(1,"aaa",1.1);   
}

}

lambda表达式创建线程

我们以往创建线程都是通过继承Thread后重写run方法,通过lambda表达式可以简化线程的创建过程

//这里是通过Thread的一个构造方法   
public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
//来创建线程
//Runnable接口中只有一个run方法,则可通过lambda表达式来代替构造方法中的Runnable
Thread t=new Thread(()->{
  for(int i=0;i<10;i++){
  System.out.println(i)
}
});
t.start();

遍历集合

我们可以调用集合中的public void forEach(Consumer <? Super E> action)方法,通过lambda表达式的方式遍历集合中的元素。
Consumer是JDK给我们提供的一个函数式接口。

@FunctionalInterface
public interface Consumer<T>{
  void acctept(T t);
}
List list=new ArraysList();
list.forEach(element->{ 
    if(element.get(i)%2==0){
    System.out.println(""+element);
}
});

删除集合中的元素

我们可以通过public boolean removeIf(Predicate<? super E> filter)方法来删除集合中的某个元素,Predicate也是JDK提供的一个函数式接口。

 ArrayList<Item> items = new ArrayList<>();
      items.add(new Item(11, "小牙刷", 12.05 ));
      items.add(new Item(5, "日本马桶盖", 999.05 ));
      items.add(new Item(7, "格力空调", 888.88 ));
      items.add(new Item(17, "肥皂", 2.00 ));
      items.add(new Item(9, "冰箱", 4200.00 ));

      items.removeIf(ele -> ele.getId() == 7);

      //通过 foreach 遍历,查看是否已经删除
      items.forEach(System.out::println);

集合内元素的排序

在以前我们要为集合内的元素进行排序,就必须要用sort方法,传入比较器匿名内部类重写Compare方法,我们现在可以使用lambda表达式来简化代码

ArrayList<Item> list = new ArrayList<>();
        list.add(new Item(13, "背心", 7.80));
        list.add(new Item(11, "半袖", 37.80));
        list.add(new Item(14, "风衣", 139.80));
        list.add(new Item(12, "秋裤", 55.33));

        /*
        list.sort(new Comparator<Item>() {
            @Override
            public int compare(Item o1, Item o2) {
                return o1.getId()  - o2.getId();
            }
        });
        */

        list.sort((o1, o2) -> o1.getId() - o2.getId());

        System.out.println(list);

lambda表达式的闭包问题

这个问题在匿名内部类也存在,若我们放开注释则会报错,这里num我们虽然没有添加final注释,但是虚拟机在编译时会自动给其添加一个final修饰关键字。

import java.util.function.Consumer;
public class Main {
    public static void main(String[] args) {

        int num = 10;

        Consumer<String> consumer = ele -> {
            System.out.println(num);
        };

        //num = num + 2;
        consumer.accept("hello");
    }
}
posted @ 2021-08-20 21:05  杨远  阅读(135)  评论(0编辑  收藏  举报