lambda表达式

1.默认方法

在java8之前子类必须实现接口所有方法。java8之后接口可以有非抽象方法,非抽象方法前面要加上default关键字,子类可以不用实现非抽象方法,也可以实现,子类根据自己需求选择实现或者不实现。接口示例如下:

public interface Add{
  int add(int i);    //抽象方法
  
  default  long add(long i){    //非抽象方法
      return i++;
  }
}

为什么要这样设计,假设java8之前Add接口是这样的:

public interface Add{
  int add(int i);
  }

现在java8要给Add接口加一个新的功能long add(long i),新的接口如下:

public interface Add{
  int add(int i);
  
  long add(long i);
}

那么我们java8之前写的代码就要改,比如我们用java6写的代码用到了Add接口,java6的代码用java8编译时就有问题,java8的Add接口中还有long add(long i)这个抽象方法,按以前的规则,就必须在旧代码中实现long add(long i)这个抽象方法,这样改动就太大了,所以java8给Add接口中新加的方法前面加上default(表示子类默认实现了这个方法),子类中就可以选择实现或者不实现,这样旧代码就不用改了。

2.函数式接口

函数式接口定义:只有一个抽象方法的接口(可以还有其他方法),下面两种接口写法都是函数式接口,都只有一个抽象方法int add(int i);

public interface Add {
    int add(int i);
}

public interface Add{
  int add(int i);
  
  default  long add(long i){   
      return i++;
  }
}

函数式接口可以显示加上@FunctionalInterface注解,也可以不加。

@FunctionalInterface
public interface Add{
  int add(int i);

  default  long add(long i){
      return i++;
  }
}

@FunctionalInterface只能加在函数式接口上,如果给非函数式接口加上会报错,如下所示:接口中有两个抽象方法,就不是函数式接口,加上@FunctionalInterface就报错。
在这里插入图片描述

函数式接口的作用:
java8之后内置了很多函数式接口,比如:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

以前我们写一个Thread,是这样写的

 Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
        });
        thread.start();

现在可以这样写,直接写run()方法里面的代码就行:

Thread thread = new Thread(
          ()->System.out.println("hello")
        );
        thread.start();

()->System.out.println(“hello”),这个写法就是lambda表达式。
因为new Thread(Runnable r)里面的参数是Runnable,而Runnable是函数式接口,只有一个抽象方法run(),所以()->System.out.println(“hello”)这样写法默认实现了这个函数式接口run()。也可以这样写:

Runnable r = ()->System.out.println("hello");
Thread thread = new Thread(r);
thread.start();

多个函数式接口怎么办
这里可以深入思考一下,如果Thread还有一个构造方法,里面也是函数式接口,比如Thread(Other o)。那么下面这种写法,调用的是Thread(Other o)还是Thread(Runnable r)?

Thread thread = new Thread(
          ()->System.out.println("hello")
        );

以下面为示例,定义两个函数式接口Add和Sub

public interface Add{
  int add(int i);
}

public interface Sub {
    int sub(int i);
}

两个函数式接口,这样写一个compute方法是没问题的,compute((i)->i)默认用的是Add接口。

public void compute(Add add){
        System.out.println("add");
}

@Test
public void test(){
     compute((i)->i);
}

如果再定义一个compute(Sub sub),compute((i)->i)就会报错,因为(i)->i,都满足Add和Sub中的函数式接口,
在这里插入图片描述
可以像下面这像写,明确指定用哪个接口

compute((Sub)(i)->i);

也可以这样写:

Sub s = (i)->i;
compute(s);

3.lambda表达式

lambda表达式基本语法是:
1.(parameters)-> expression
parameters是参数,可以为空,expression就是执行一条语句。示例:

() -> {}      //空的,什么也不执行
(String str) -> System.out.println(str)   //输出str
() -> "hello"           //返回hello
() -> return "hello"  //返回hello,和上面效果一样
(int i,int j) -> i+j       // 返回i+j

2. (parameters) -> {statements;}
注意statements后面有分号,有分号就是代码块,即使只有一条语句也是代码块,要加上{}。
parameters是参数,可以为空,statements是多条语句,就是一段代码块,示例:

(int i) -> {
              i++;
              if(i>0){
              }else {
              }
              return "";
       }

下面这是错误写法:

() -> return "hello"; 

因为后面加了分号,就是代码块,要加上{},
改成这样 () -> {return “hello”;} ,或者去掉分号() -> return “hello”

总结一下,如果一个方法的参数是函数式接口,那么我们可以写一个lambda表达式传给这个方法。
下面看一个完整示例, 体会一下函数式接口和lambda的功能:

public interface NumberFilter {
    boolean filter(Integer i);
}

public List<Integer> numberFiler(List<Integer> list,NumberFilter filter){
        List<Integer> resultList = new ArrayList<>();
        for(Integer i:list){
            if(filter.filter(i)){
                resultList.add(i);
            }
        }
        return  resultList;
    }

@Test
public void myNumberFilterTest(){
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        NumberFilter a = (Integer i) -> i%2==0;   //单语句lambda表达式,过滤出偶数
        System.out.println(numberFiler(list,a));   输出[2,4]

        NumberFilter b = (Integer i) -> {           //语句块lambda表达式,过滤出奇数
            if(i%2==0){
                return false;
            }else {
                return true;
            }
        };   
        System.out.println(numberFiler(list,b));   输出[1,3,5]
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值