lambad表达式(深入详解)

Lamdba表达式的标准格式

组成Lamdba表达式的三要素:形式参数,箭头,代码块

(形式参数)->{
    代码块
}

形式参数:如果有多个参数,参数之间用逗号隔开;如果只有一个参数可以不要(),如果没有参数留空即可

->:由英文中画线和大于符号组成,固定写法。代表指向动作

代码块:是我们具体要做的事情,也就是以前我们写的方法体内容,如果方法体不止一行,需要用上 {} ,如果

以下是lambda表达式的重要特征:

* lambda表达式的左边

* 1、如果没有参数的话,可以直接一个括号,类型的话,都可以省

* 2、如果只有一个参数的话,可以直接传入参数,并省略括号。

* 3、如果有两个参数的话,需要直接传入两个参数

*

* lambda表达式的右边

* 1、如果只执行一条语句的话,就直接可以省略大括号

* 2、如果只执行一条语句,并且有返回值的话,可以省略大括号

* 3、如果执行多条语句的话,就要运用到大括号来执行了。

下面对每个语法格式的特征进行举例说明:

(1)语法格式一:无参,无返回值,Lambda体只需一条语句。如下
  @Test
  public void test01(){
    Runnable runnable=()-> System.out.println("Runnable 运行");
    runnable.run();//结果:Runnable 运行
  }
(2)语法格式二:Lambda需要一个参数,无返回值。如下:
  @Test
  public void test02(){
    Consumer<String> consumer=(x)-> System.out.println(x);
    consumer.accept("Hello Consumer");//结果:Hello Consumer
  }
(3)语法格式三:Lambda只需要一个参数时,参数的小括号可以省略,如下:
  public void test02(){
    Consumer<String> consumer=x-> System.out.println(x);
    consumer.accept("Hello Consumer");//结果:Hello Consumer
  }
(4)语法格式四:Lambda需要两个参数,并且Lambda体中有多条语句。
  @Test
  public void test04(){
    Comparator<Integer> com=(x, y)->{
      System.out.println("函数式接口");
      return Integer.compare(x,y);
    };
    System.out.println(com.compare(2,4));//结果:-1
  }
(5)语法格式五:有两个以上参数,有返回值,若Lambda体中只有一条语句,return和大括号都可以省略不写
@Test
    public void test05(){
    Comparator<Integer> com=(x, y)-> Integer.compare(x,y);
    System.out.println(com.compare(4,2));//结果:1
}
(6)Lambda表达式的参数列表的数据类型可以省略不写,因为JVM可以通过上下文推断出数据类型,即“类型推断”
@Test
    public void test06(){
    Comparator<Integer> com=(Integer x, Integer y)-> Integer.compare(x,y);
    System.out.println(com.compare(4,2));//结果:1
}

函数式接口

什么是函数式接口

==只包含一个抽象方法的接口,就称为函数式接口。==我们可以通过Lambda表达式来创建该接口的实现对象。

我们可以在任意函数式接口上使用@FunctionalInterface注解,这样做可以用于检测它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。

自定义函数式接口

按照函数式接口的定义,自定义一个函数式接口,如下:

@FunctionalInterface
public interface MyFuncInterf<T> {
   public T getValue(String origin);
}

定义一个方法将函数式接口作为方法参数

  public String toLowerString(MyFuncInterf<String> mf,String origin){
    return mf.getValue(origin);
  }

将Lambda表达式实现的接口作为参数传递

public void test07(){
    String value=toLowerString((str)->{
        return str.toLowerCase();
    },"ABC");
    System.out.println(value);//结果ABC
}

Java内置函数式接口

四大核心函数式接口的介绍,如图所示

其他接口的定义,如图所示:

方法引用

当要传递给Lambda体的操作,已经有实现的方法了,就可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用的参数列表一致,方法的返回值也必须一致,即方法的签名一致)。方法引用可以理解为方法引用是Lambda表达式的另外一种表现形式。

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

方法引用的使用情况共分为以下三种:

  • 对象::实例方法名

  • 类::静态方法名

  • 类::实例方法名

举例

比如,这里我们随机生成10个整数然后取它们绝对值并一一打印出来。

new Random().ints(10)
        .map(i->Math.abs(i))
        .forEach(i -> System.out.println(i));

map方法接受的是一个函数式接口IntUnaryOperator,那么上面代码中的i->Math.abs(i)实际上是

new IntUnaryOperator() {
    @Override
    public int applyAsInt(int operand) {
        return Math.abs(operand);
    }
}

从上面来看IntUnaryOperator就是代理了Math.abs(int i),参数列表、返回值都相同,而且没有掺杂其它额外的逻辑。这一点非常重要,不掺杂其它逻辑才能相互代替。那么就可以通过方法引用来简化Lambda 表达式。上面的式子就可以简化为:

new Random().ints(10)
        .map(Math::abs)
        .forEach(System.out::println);

Java 方法引用Java 8随着Lambda表达式引入的新特性。 可以直接引用已有Java类或对象的方法或构造器。方法引用通常与Lambda表达式结合使用以简化代码。其使用条件是:Lambda表达式的主体仅包含一个表达式,且Lambda表达式只调用了一个已经存在的方法;被引用的方法的参数列表和返回值与Lambda表达式的输入输出一致

方法不够“单纯”的引用

格式

方法引用的格式为<ClassName | instance>::<MethodName>。也就是被引用的方法所属的类名和方法名用双冒号::隔开,构造器方法是个例外,引用会用到new关键字,总结了一下:

引用方式

说明

静态方法引用

ClassName :: staticMethodName 例如上面的Math::abs

构造器引用

ClassName :: new 例如通过Supplier<T> 返回新实例

类任意实例方法引用

ClassName :: instanceMethodName 例如 String::concat

类特定实例方法引用

instance:: instanceMethodName 例如 this::equals

关于可读性分析

大部分人认为Lambda 表达式存在阅读困难的问题,其实不然,这种流水线的结构恰恰增加了可读性,每一个Lambda 表达式都可以看作一个执行策略,方法引用反而让你能更加清楚执行了什么策略。另外我经常见到类似如下的流式写法:

new Random().ints(10)
        .map(operand -> {
            System.out.println("operand = " + operand);
            return operand+1;
        })
        .forEach(System.out::println);

//方法引用
public void randomInt() {
    new Random().ints(10)
            .map(this::selfIncreasing)
            .forEach(System.out::println);

}

// 封装
private int selfIncreasing(int self){
    System.out.println("self = " + self);
    return self+1;
}

这样反而可读性很强,随机取10个数,然后每个数走个自增并分别打印出来。

总结

方法引用实现在特定场景下Lambda表达式的简化表示,目的在于让代码更加简洁。

Lambda表达式的优缺点

优点:

使代码更简洁,紧凑

可以使用并行流来并行处理,充分利用多核CPU的优势

有利于JIT编译器对代码进行优化

缺点:

非并行计算情况下,其计算速度没有比传统的 for 循环快

不容易调试

若其他程序员没有学过 Lambda 表达式,代码不容易看懂

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值