Lambda表达式

Lambda表达式(也称为闭包)是整个Java 8发行版中最受期待的在Java语言层面上的改变,Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中),或者把代码看成数据。


一个lambda可以由用逗号分隔的参数列表、–>符号与函数体三部分表示。

lambda表达式的一般语法:

 (Type1 param1, Type2 param2, ..., TypeN paramN) -> {

  statment1;

  statment2;

  //.............

  return statmentM;

}

List<String> names = Arrays.asList("d", "b", "c", "a");
Collections.sort(names, (String o1, String o2) -> {
                System.out.print(o1);
                System.out.print(o2);
                return o1.compareTo(o2);
            });
            System.out.println("\n" + names);


简化版:

1.参数类型省略–绝大多数情况,编译器都可以从上下文环境中推断出lambda表达式的参数类型。这样lambda表达式就变成了:

(param1,param2, ..., paramN) -> {

  statment1;

  statment2;

  //.............

  return statmentM;

}


Collections.sort(names, (o1, o2) -> {
                System.out.print(o1);
                System.out.print(o2);
                return o1.compareTo(o2);
            });
            System.out.println("\n" + names);


2. 当lambda表达式的参数个数只有一个,可以省略小括号。lambda表达式简写为:

 param1 -> {

  statment1;

  statment2;

  //.............

  return statmentM;

}


Arrays.asList( "a", "b", "d" ).forEach( e -> {
	System.out.println( e ) ;
});


3. 当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的分号。lambda表达式简化为:

param1 -> statement

Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

Collections.sort(names, (o1, o2) -> o1.compareTo(o2));


  • Lambda表达式一个常见的用法是取代(某些)匿名内部类

new Thread(new Runnable(){

    @Override

    public void run(){

        System.out.println("Thread run()");

    }

}).start();


Lambda表达式之后,则可以这样写: 

new Thread(

        () -> System.out.println("Thread run()")

).start();


详见: 函数式接口

  • Lambda表达式的另一个重要用法,是和Stream一起使用

Stream就是一组元素的序列,支持对这些元素进行各种操作,而这些操作是通过Lambda表达式指定的。可以把Stream看作Java Collection的一种视图,就像迭代器是容器的一种视图那样(但Stream不会修改容器中的内容)。Stream仅仅代表着数据流,并没有数据结构,所以他遍历完一次之后便再也无法遍历(这点在编程时候需要注意,不像Collection,遍历多少次里面都还有数据),它的来源可以是Collection、array、io等等。

可以把Stream当成一个高级版本的Iterator。原始版本的Iterator,用户只能一个一个的遍历元素并对其执行某些操作;高级版本的Stream,用户只要给出需要对其包含的元素执行什么操作,比如“过滤掉长度大于10的字符串”、“获取每个字符串的首字母”等,具体这些操作如何应用到每个元素上,就给Stream就好了!


Stream和Collection不同之处:

·      不存储数据。 流不是一个存储元素的数据结构。 它只是传递源(source)的数据。

·      功能性的(Functional in nature)。在流上操作只是产生一个结果,不会修改源。 例如filter只是生成一个筛选后的stream,不会删除源里的元素。

·      延迟搜索。 许多流操作, 如filter, map等,都是延迟执行。 中间操作总是lazy的。

·      Stream可能是无界的。 而集合总是有界的(元素数量是有限大小)。 短路操作如limit(n), findFirst()可以在有限的时间内完成在无界的stream

·      可消费的(Consumable)。 不是太好翻译,意思流的元素在流的声明周期内只能访问一次。 再次访问只能再重新从源中生成一个Stream

 

下面例子展示了Stream的常见用法。

例1

假设需要从一个字符串列表中选出以数字开头的字符串并输出,Java 7之前需要这样写:

List<String> list = Arrays.asList("1one", "two", "three", "4four");
            for (String str : list) {
                if (Character.isDigit(str.charAt(0))) {
                    System.out.println(str);
                }
            }

而Java 8就可以这样写:

 List<String> list = Arrays.asList("1one", "two", "three", "4four");
            list.stream()// 1.得到容器的Steam
                .filter(str -> Character.isDigit(str.charAt(0)))// 2.选出以数字开头的字符串
                .forEach(str -> System.out.println(str));// 3.输出字符串

上述代码首先

1. 调用List.stream()方法得到容器的Stream

2. 然后调用filter()方法过滤出以数字开头的字符串,

3. 最后调用forEach()方法输出结果。

使用Stream有两个明显的好处:

1.  减少了模板代码,只用Lambda表达式指明所需操作,代码语义更加明确、便于阅读。

2.  将外部迭代改成了Stream的内部迭代,方便了JVM本身对迭代过程做优化(比如可以并行迭代)

 

例2

假设需要从一个字符串列表中,选出所有不以数字开头的字符串,将其转换成大写形式,并把结果放到新的集合当中。Java 8书写的代码如下:

List<String> list = Arrays.asList("1one", "two", "three", "4four");
            Set<String> newList =
                    list.stream()// 1.得到容器的Stream
                        .filter(str -> !Character.isDigit(str.charAt(0)))// 2.选出不以数字开头的字符串
                        .map(String::toUpperCase)// 3.转换成大写形式
                        //.map(str -> str.toUpperCase())
                        .collect(Collectors.toSet());// 4.生成结果集
            System.out.println(newList);

上述代码首先

1. 调用List.stream()方法得到容器的Stream

2. 然后调用filter()方法选出不以数字开头的字符串,

3. 之后调用map()方法将字符串转换成大写形式,

4. 最后调用collect()方法将结果转换成Set。这个例子还向我们展示了方法引用(method references)以及收集器(Collector)的用法。

通过这个例子我们看到了Stream链式操作,即多个操作可以连成一串。不用担心这会导致对容器的多次迭代,因为不是每个Stream的操作都会立即执行。Stream的操作分成两类,一类是中间操作(intermediate operations),另一类是最终操作(terminal operation),只有最终操作才会导致真正的代码执行,中间操作只会做一些标记,表示需要对Stream进行某种操作。这意味着可以在Stream上通过关联多种操作,但最终只需要一次迭代。


详见: Stream API


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值