Lambdda 表达式


  在Java的语言世界里面,除了基本的数据类型,一切都是对象,例如:String字符串、每个对象实例、数组这些都是对象。在Java中方法是不能完全独立存在的,不能将方法作为参数或者返回值给实例。注意:方法(Method),函数(Function),在Java中是没有函数的,因为Java是一个面向对象编程的语言;函数更多的意义是用来表述面向过程的语言;又或者说”函数是大家的函数,方法是类的方法”,不过,不用这么纠结,我们可以认为在Java中方法就是函数,函数就是方法。

为什么出现Lambda表达式

  从线程的构建、自定义比较器、Swing等等,这些我们都是匿名内部类的方式去书写。为了简化这些代码的书写,使得代码更加紧凑,更为了使得Java拥有函数式编程的特点。javaScript是典型的函数式编程语言,点击这里以及这里了解,函数式语言提供了一种强大的功能–闭包,闭包的特点是词法的作用域与把函数当作值来传递。虽然闭包与Lambda表达式之间存在显著差别,但是Lambda表达式至少是很好的闭包替代者。

Lambda表达式是什么

  在Java中,刚开始说过,除了基本的数据类型,一切都是对象,那么Lambda表达式也是对象,所以必须依赖于一种特殊的对象类型–函数式接口(Function Interface)。Lambda表达式可以理解为刚开始说的匿名内部类函数,它没有声明方法,没有访问修饰符,没有返回值声明和名字。

Lambda表达式的特征

  • 可选型声明:不需要声明参数类型,编译器可以统一识别参数值;
  • 可选的参数圆括号:一个参数且类型可推导时,无需定义圆括号,但是多个参数需要定义圆括号;
  • 可选的大括号:如果函数主体包含了一个语句,不需要大括号;
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要显式指定表达式返回值。

Lambda表达式的用法

  • Lambda表达式语法:(parameters)->expression 或 (parameters)->{statements}
    Lambda表达式语法解析:parameters:参数 expression:表达式(一条语句) statements:陈述(多个语句)
  • 用法
    1. 替代匿名内部类
    实现Runnable接口是匿名内部类的典型例子
    java // 代码示例 public void runable() { new Thread(new Runnable() { @Override public void run() { System.out.println("the old runnable now is useing"); } }).start(); new Thread(() -> System.out.println("the new runnable now is useing")).start(); }
    2. 集合的迭代
    使用Lambda表达式对map集合进行迭代遍历
    java // 代码示例 private void listiterator() { List<String> languages = Arrays.asList("java", "python", "javaScript"); languages.forEach(x -> System.out.println(x)); }
    3. 实现map
    使用Lambda表达式实现map,map的作用是把一个对象换做另一个,这块涉及到Java8的新特性Stream,下一篇博客会讲。
    java // 代码示例 private void mapFunction(){ List<Double> languages = Arrays.asList(2.0, 4.0, 6.0); languages.stream().map(x -> x + x * 0.5).forEach((x) -> System.out.println(x)); }
    4. 实现reduce
    使用Lambda表达式实现reduce,reduce是将所有的值合并为一个,这块涉及到Java8的新特性Stream,下一篇博客会讲。
    java // 代码示例 private void sumFunction() { List<Double> cost = Arrays.asList(2.0, 4.0, 6.0); double doubleCode = cost.stream().reduce((sum, x) -> sum + x).get(); System.out.println(doubleCode); }
    5. 过滤操作
    使用Lambda表达式实现对集合的过滤,filter过滤掉集合中的部分元素,这块涉及到Java8的新特性Stream,下一篇博客会讲。
    java // 代码示例 private void filterFunction() { List<Double> cost = Arrays.asList(2.0, 4.0, 6.0); //方式一 cost.stream().filter(x -> x > 3).collect(Collectors.toList()).stream().forEach(x -> System.out.println(x)); //方式二 List<Double> doubleCode = cost.stream().filter(x -> x > 3).collect(Collectors.toList()); doubleCode.stream().forEach(x -> System.out.println(x)); }
    6. 与工具包java.util.function配合
    Java8除了在语言层面支持了函数式编程,而且增添了一个新包,包名叫java.util.function。该包包含了很多类,来支持Java的函数式编程,其中一个类是Predicate,使用java.util.function.Predicate 函数式接口以及lambda表达式,可以向API方法添加逻辑,用更少的代码支持更多的动态行为。Predicate接口非常适用于做过滤。该包下的其他类放到姐妹篇里面讲解

    |函数式接口名 | 作用|
    | — | — |
    |Function<T, R> | 接受一个参数T,返回结果R|
    |Predicate | 接受一个参数T,返回boolean|
    |Supplier | 不接受任何参数T,返回结果T|
    |Consumer | 接受一个参数T,不返回结果|
    |UnaryOperator | 继承自Function<T,T>,返回相同类型T的结果|
    |BiFunction<T, U, R>|接收两个参数T,U,返回结果R|
    |BinaryOperator|继承自BiFunction<T,T,T>,返回相同类型T的结果|
    |Runnable|实际上不接受任何参数,也不返回结果|
    |Comparable|实际上是接受两个相同类型的T,返回int|
    |Callable|不接受任何参数,返回结果V|

    java // 代码示例 public class test { public static void main(String[] args) { test t = new test(); List<String> launges = Arrays.asList("java", "shell", "python"); t.functionTest.apply(launges).stream().forEach(x -> System.out.println(x)); boolean flg = t.predicateTest.test(launges); System.out.println(flg); } private Function<List<String>, List<String>> functionTest = in -> { return in.stream().filter(x -> x.startsWith("j")).collect(Collectors.toList()); }; private Predicate<List<String>> predicateTest = in -> { return in.stream().filter(x -> x.startsWith("j")).count() > 0; }; }

Lambda表达式的优劣

  • 优势
    1. 代码简洁
    2. 易并行计算
    3. 方便了函数式编程
    4. 改善了集合的操作(引入了Stream API)
  • 劣势
    1. 代码可读性变差
    2. Debug调试变得困难
    3. 不可以直接在foreach中修改外面的值
    4. 在很多非并行运算中,性能未必有传统的for性能要高

文章借鉴处


文章作者: Huowy
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Huowy !
评论
  目录