java8|java8 lambda

定义

“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。
java8增加了对函数式编程的支撑,即java8 lambda表达式。通过lambda表达式可以方便程序员将代码作为数据进行传递,可以赋值给一个变量也可以作为函数参数、返回值来使用,类似于java的匿名内部类。
入门例子 当前开发使用最多的就是多线程,
  • 在java中一般是通过实现Runnable接口,如下
    new Thread(new Runnable() { @Override public void run() { System.out.println("Hello world!"); } }).start();

  • 在java8中可以使用lambda表达式形式,更简单,如下
    new Thread( () -> System.out.println("Hello world!") ).start();

java8 lambda语法
  • 基本语法
    (parameters) -> expression

    (parameters) ->{ statements; }
说明:parameters可以带参数类型也可以省略参数类型,但省略参数类型时必须能保证jdk自动推断
  • 函数接口
函数接口是只有一个抽象方法的接口,用作Lambda表达式的类型,可以使用@FunctionalInterface注解标注。接口中单一方法的命令并不重要,只要方法签名和Lambda表达式的类型匹配。
  • JDK中默认提供的函数接口
接口 参数 返回类型 示例
Predicate T boolean 判断结果的真假,是与否等
Consumer T void 输出一个值,像上面线程
Function T R 获得一个对象的名字
Supplier None T 工厂方法
UnaryOperator T T 逻辑非(!)
BinaryOperator (T,T) T 求两个数的乘积(*)
java8 Stream java8 不仅在语言层面支持了lambda表达式,还为此对类库做了改进,包括集合类的API以及引入的流(Stream),Stream很多方法的参数都是lambda表达式。
  • 内部迭代和外部迭代
    相对于集合代码来说的,像常用的for/while循环通过产生新的Iterator对象来控制整个迭代过程,就是外部迭代。而java8中集合对你的stream()方法直接是使用Stream对集合中的数据进行迭代,就是内部代码。
    List list = new ArrayList<>(); list.add("hello"); list.add("world"); list.add("!"); //外部迭代 for (String s : list) { System.out.println(s); }//内部迭代 list.stream().forEach(e -> System.out.println(e));

  • 惰性求值
    在Stream的操作中,有一些像filter方法只描述Stream,并不会产生一个新的集合的方法,叫做惰性求值方法;就像医生开的药方,并不是具体的药品。
  • 【java8|java8 lambda】及早求值
    在Stream的操作中,还有一类像count这种方法最终会从Stream中产生最终值,叫做及早求值方法;这个已经是根据药方获取到相应药品了。
判断惰性求值还是及早求值很简单:返回Stream对象就是惰性求值;返回另外类型的值或者空,则是及早求值。
对Stream最理想的操作是形成一个惰性求值链,最后用一个及早求值的操作返回想要的结果。
long num = list.stream().filter(s -> s.length() > 2).count(); System.out.println("num: " + num); ---------------------------------------------------------- 输出:num: 2

java8 常用的Stream操作
  • collect(toList())
    将一个流中的值生成一个列表,及早求值函数。是一个通用的结构。
List list = Stream.of("hello", "world", "!").collect(Collectors.toList());

  • map
    如果一个函数可以将一种类型的值转换成另外一种类型,则map就可以使用此函数将一个流中的值转换成一个新的流。例如将字符串字符全大写
List collect = Stream.of("hello", "world", "!").map(s -> s.toUpperCase()).collect(Collectors.toList()); collect.stream().forEach(s -> System.out.print(s + " ")); ------------------------------------------------------ 输出:HELLO WORLD !

map函数接收一个Function类型的参数。
  • filter
    遍历数据并检查其中的元素是filer的本职工作。例子可以参考前面的。
filter函数增收一个Predicate类型的参数
  • flatMap
    与map类似,可以将Stream中的值进行替换;与map不一样的是flatMap可以将多个Stream连接成一个Stream
List together = Stream.of(asList("a", "b"), asList("c", "d")).flatMap(s -> s.stream()).collect(Collectors.toList());

与map一样接收一个Function类型参数,不过R的类型限定为一个Stream类型。
  • max和min
    Stream上常用的操作之一是求最大或者最小值。这个要考虑的是用什么作为排序的指标,例如数值大小、字符串长度、字典序等等。
System.out.println("max: " + Stream.of(asList(1, 2), asList(3, 4)).flatMap(s -> s.stream()).max(Comparator.comparing(n -> n)).get()); System.out.println("min: " + Stream.of(asList(1, 2), asList(3, 4)).flatMap(s -> s.stream()).min(Comparator.comparing(n -> n)).get()); ---------------------------------------------------------------------- 输出:max: 4 min: 1

接收一个Comparator对象,此类提供了一个静态函数comparing可以方便用户实现一个比较器。此函数参数、返回值都是lambda表达式。返回的是一个Optional对象(后面再专门讨论),需要使用get方法获取相应的值。
  • reduce
    实现从一组值中生成一个值。前面例子中的count、max、min方法就是reduce操作,只是已经纳入了标准库中了。使用reduce实现数字累加,如下
System.out.println("sum: " + Stream.of(1,2,3).reduce(0, (acc,elment) -> acc + elment)); ------------------------------------ 输出:sum: 6

reduce第1个参数是初始值,第二个参数叫reducer,是一个BinaryOperator类型的lambda表达式。
参考 《java 8函数式编程》
http://www.importnew.com/16436.html

    推荐阅读