前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDK1.8之Lambada表达式

JDK1.8之Lambada表达式

作者头像
小东啊
发布2019-06-26 15:16:22
1.3K0
发布2019-06-26 15:16:22
举报

Lambda 表达式 − Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中。

lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda表达式还增强了集合库。 Java SE 8添加了2个对集合数据进行批量操作的包: java.util.function 包以及java.util.stream 包。 流(stream)就如同迭代器(iterator),但附加了许多额外的功能。 总的来说,lambda表达式和 stream 是自Java语言添加泛型(Generics)和注解(annotation)以来最大的变化。 在本文中,我们将从简单到复杂的示例中见认识lambda表达式和stream的强悍。

语法

lambda 表达式的语法格式如下:

(parameters) -> expression 或 (parameters) ->{ statements; }

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

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

Lambda 表达式的简单例子:

// 1. 不需要参数,返回值为 5  () -> 5  
// 2. 接收一个参数(数字类型),返回其2倍的值  x -> 2 * x  
// 3. 接受2个参数(数字),并返回他们的差值  (x, y) -> x – y  
// 4. 接收2个int型整数,返回他们的和  (int x, int y) -> x + y  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  (String s) -> System.out.print(s)

基本的Lambda例子

现在,我们已经知道什么是lambda表达式,让我们先从一些基本的例子开始。 在本节中,我们将看到lambda表达式如何影响我们编码的方式。 假设有一个玩家List ,程序员可以使用 for 语句 ("for 循环")来遍历,在Java SE 8中可以转换为另一种形式:

        // 字符串数组        String[] atp = {"Brandon", "Mason", "Elijah"};        List<String> players = Arrays.asList(atp);
        // java8之前        for (String player : players) {            System.out.println(player + "; ");        }        // 使用 lambda 表达式以及函数操作        players.forEach((player) -> System.out.println(player + "; "));        // 在 Java 8 中使用双冒号操作符        players.forEach(System.out::println);

lambda表达式可以将我们的代码缩减到一行

使用Lambda排序集合

在Java中,Comparator 类被用来排序集合。 在下面的例子中,我们将根据球员的 name, surname, name 长度 以及最后一个字母。 使用匿名内部类来排序,然后再使用lambda表达式精简我们的代码。 在第一个例子中,我们将根据name来排序list。 使用旧的方式,代码如下所示:

// 使用匿名内部类根据 长度 排序 players        players.sort(new Comparator<String>() {            @Override            public int compare(String o1, String o2) {                return o1.length() - o2.length();            }        });
        players.sort((String s1, String s2) -> (s1.length() - s2.length()));
        System.out.println(players);

就是这样,简洁又直观。 在下面我们将探索更多lambdas的能力,并将其与 stream 结合起来使用。

使用Lambdas和Streams

Stream是对集合的包装,通常和lambda一起使用。 使用lambdas可以支持许多操作,如 map, filter, limit, sorted, count, min, max, sum, collect 等等。 同样,Stream使用懒运算,他们并不会真正地读取所有数据,遇到像getFirst() 这样的方法就会结束链式语法。 在接下来的例子中,我们将探索lambdas和streams 能做什么。 我们创建了一个User类并使用这个类来添加一些数据到list中,将用于进一步流操作。 User 只是一个简单的POJO类:

package com.li.springbootthymeleaf;
/** * @Classname User * @Description 用户实体类 * @Author 李号东 lihaodongmail@163.com * @Date 2019-04-29 13:54 * @Version 1.0 */public class User {
    private String name,age;
    public User(String name,String age){        this.name = name;        this.age = age;    }
    public String getName() {        return name;    }
    public void setName(String name) {        this.name = name;    }
    public String getAge() {        return age;    }
    public void setAge(String age) {        this.age = age;    }}

接下来,我们将创建两个list,都用来存放User对象:

List<User> usersOne = new ArrayList<User>(){            {                add(new User("小王",18));                add(new User("小李",18));                add(new User("小刘",18));                add(new User("小张",18));            }        };
        List<User> usersTwo = new ArrayList<User>(){            {                add(new User("小高",18));                add(new User("小陈",18));                add(new User("小沈",18));                add(new User("小罗",18));            }        };

现在我们使用forEach方法来迭代输出内容:

usersOne.forEach(user -> {System.out.printf("%s %s; ",user.getName(), user.getAge());});usersTwo.forEach(user -> {System.out.printf("%s %s; ",user.getName(), user.getAge());});

我们同样使用forEach方法,增加用户的年龄:

System.out.println("所有用户年龄加5岁");        Consumer<User> addAge = e -> e.setAge(e.getAge() + 5);        usersOne.forEach(addAge);        usersTwo.forEach(addAge);        System.out.println("加完后年龄:");        usersOne.forEach(user -> {            System.out.printf("%s %s; ", user.getName(), user.getAge());        });        usersTwo.forEach(user -> {            System.out.printf("%s %s; ", user.getName(), user.getAge());        });

另一个有用的方法是过滤器filter() ,让我们显示用户为小王的:

usersOne.stream().filter((p) -> ("小王".equals(p.getName())))                .forEach((user) -> System.out.printf("%s %s; ", user.getName(), user.getAge()));

我们也可以定义过滤器,然后重用它们来执行其他操作:

// 自定义过滤器 年龄大于18的Predicate<User> ageFilter = (p) -> (p.getAge() > 18);
usersOne.stream().filter(ageFilter).forEach((user) -> System.out.printf("%s %s; ", user.getName(), user.getAge()));

使用limit方法,可以限制结果集的个数:

System.out.println("最前面的3个用户:");        usersOne.stream().limit(3)                .forEach((user) -> System.out.printf("%s %s; ", user.getName(), user.getAge()));System.out.println("最前面的3个年龄大于18的");        usersOne.stream()                .filter(ageFilter)                .limit(3)                .forEach((user) -> System.out.printf("%s %s; ", user.getName(), user.getAge()));

排序呢? 我们在stream中能处理吗? 答案是肯定的。 在下面的例子中,我们将根据名字放到一个list中,然后显示列表:

System.out.println("排序");        List<User> collect = usersOne                .stream()                .sorted((u, u2) -> (u.getName().compareTo(u2.getName())))                .limit(3)                .collect(toList());
        collect.forEach(user -> {System.out.printf("%s %s; ", user.getName(), user.getAge());});

如果我们只对年龄大小感兴趣,比排序后选择第一个/最后一个 更快的是min和max方法:

System.out.println("年龄最小的:");        User user = usersOne                .stream()                .min((u1, u2) -> (u1.getAge() - u2.getAge()))                .get();
        System.out.printf(" %s %s;", user.getName(), user.getAge());
        System.out.println("年龄最大的:");        User user1 = usersOne                .stream()                .max((u1, u2) -> (u1.getAge() - u2.getAge()))                .get();
        System.out.printf(" %s %s;", user1.getName(), user1.getAge());

上面的例子中我们已经看到 collect 方法是如何工作的。 结合 map 方法,我们可以使用 collect 方法来将我们的结果集放到一个字符串,一个 Set 或一个TreeSet中:

System.out.println("将 usersOne 的name 拼接成字符串:");        String us = usersOne                .stream()                .map(User::getName)                .collect(joining("; "));
        System.out.println(us);
        System.out.println("将 usersOne 的name 存放到 Set:");        Set<String> usSet = usersOne                .stream()                .map(User::getName)                .collect(toSet());
        System.out.println(usSet);
        System.out.println("将 usersOne 的name 存放到 TreeSet:");        TreeSet<String> usTreeSet = usersOne                .stream()                .map(User::getName)                .collect(toCollection(TreeSet::new));
        System.out.println(usTreeSet);

Streams 还可以是并行的(parallel)。 示例如下:

System.out.println("计算所有用户的所有年龄和:");        int totalAge = usersOne                .parallelStream()                .mapToInt(p -> p.getAge())                .sum();
        System.out.println(totalAge);

我们可以使用summaryStatistics方法获得stream 中元素的各种汇总数据。 接下来,我们可以访问这些方法,比如getMax, getMin, getSum或getAverage:

//计算 count, min, max, sum, and average for numbers        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);        IntSummaryStatistics stats = numbers                .stream()                .mapToInt((x) -> x)                .summaryStatistics();
        System.out.println("List中最大的数字 : " + stats.getMax());        System.out.println("List中最小的数字 : " + stats.getMin());        System.out.println("所有数字的总和   : " + stats.getSum());        System.out.println("所有数字的平均值 : " + stats.getAverage());

下面是使用lambdas 来实现 Runnable接口 的示例:

// 使用匿名内部类        new Thread(new Runnable() {            @Override            public void run() {                System.out.println("Hello world !");            }        }).start();
        // 使用 lambda expression        new Thread(() -> System.out.println("Hello world !")).start();
        // 使用匿名内部类        Runnable race1 = new Runnable() {            @Override            public void run() {                System.out.println("Hello world !");            }        };        // 使用 lambda expression        Runnable race2 = () -> System.out.println("Hello world !");        // 直接调用 run 方法        race1.run();        race2.run();

ok 目前能想到的只有这么多 希望喜欢

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 李浩东的博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 语法
  • Lambda 表达式的简单例子:
  • 基本的Lambda例子
  • 使用Lambda排序集合
  • 使用Lambdas和Streams
  • 下面是使用lambdas 来实现 Runnable接口 的示例:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档