Java 中的 Lambda 表达式

Java 中的 Lambda 表达式

本文连接:https://code.csdn.net/liuche911/lambdainjava/file/LambdainJava.md

本文翻译自Oracle官方Java教程 "The Java(TM) Tutorials" 中的Lambda表达式一节。我从新写了代码,所以可能跟原文不大一样。

另外就是我没有搜索是否有人已经翻译过这段教程,同时我相信网上关于Lambda表达式的帖子多如牛毛。。。本文作为自我总结的意义显然高于传播技术 :)

先看一个例子

假设我们有一个 Person 类,大致如下:

```Java
public class Person {
    private String name;
    private int age;

    public static enum Sex {
        MALE, FEMALE
    };  
    private Sex sex;
    private double height;
    private double weight;

    public Person(String name, int age, Sex sex, double height, double weight) {
        super();
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.height = height;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return String.format("%s Age:%d, Sex:%s%n", name, age,
                sex == Sex.MALE ? "male" : "female");
    }

    //省略了set&get方法

}
```

再来一个 PersonList 类存放一组人,大致如下

```Java
public class PersonList {

    private List<Person> persons;

    public PersonList(List<Person> persons) {
        super();
        this.persons = persons;
    }

    public boolean addPerson(Person person) {
        return this.persons.add(person);
    }

    public boolean removePerson(Person person) {
        return this.persons.remove(person);
    }
}
```

在给个简单的测试函数吧,假设就在 main 函数里实现:

```Java
    public static void main(String[] args) {
        PersonList personList = new PersonList(new ArrayList<Person>());
        personList.addPerson(new Person("老王", 88, Person.Sex.MALE, 1.7, 60));
        personList.addPerson(new Person("小丽", 12, Person.Sex.FEMALE, 1.60, 40));
        personList.addPerson(new Person("小白", 19, Person.Sex.MALE, 1.78, 66));
        personList.addPerson(new Person("小美", 22, Person.Sex.FEMALE, 1.7, 50));
    }
```

现在我们需要编写一个函数,找出这一组人里,年纪小于等于(比方说)50岁的人,该怎么办呢?

普通青年的做法

```Java
    /**
     * 普通青年 返回年纪小于age的人
     * 
     * @param age
     *            小于该年龄
     */
    public void printPersonAgeYoungerThan(int age) {
        for (Person p : persons) {
            if (p.getAge() <= age) {
                System.out.println(p.toString());
            }
        }
    }
```

这样做固然是满足需求,而且还没有“二逼”到 if (p.getAge() <= 50) 的地步,些许还有点灵活性;但是如果用户还想查询年纪大于50的人呢?再写一个函数?那么查询年纪大于18又小于50的人呢?且看文艺青年是怎么做的:

文艺青年的做法

```Java
    /**
     * 文艺青年 返回年纪大于等于low,小于等于high的人
     * 
     * @param low
     * @param high
     */
    public void printPersonAgeIn(int low, int high) {
        for (Person p : persons) {
            if (p.getAge() >= low && p.getAge() <= high) {
                System.out.println(p.toString());
            }
        }
    }
```

这下似乎好多了,“小于等于50岁”可以理解为“大于等于-100岁,小于等于50岁”。大于多少岁的时候,上界即使不放心,那就飚到10000岁!再不放心就 Integer.MAX_VALUE ,内心终于得到平静……

不过呀,用户可能还没完,他说不定想查询“满足美国服义务兵役条件的人~”,即“年龄在18到25岁的男性”。嘿嘿,烦了吧,还好我们有更厉害的程序猿青年!

程序猿青年的做法

```Java
    public static interface CheckPersons {
        boolean test(Person p);
    }

    /**
     * 程序猿:返回满足CheckPersons tester的test方法的人
     * 
     * @param tester
     */
    public void printPersonAccordinTester(CheckPersons tester) {
        for (Person p : persons) {
            if (tester.test(p)) {
                System.out.println(p.toString());
            }
        }
    }
```

你再看~作为API提供者,我不干啦,接口甩出来,调用放好,从此放权给用户,想查询什么条件,自己写吧,我都能满足你。那么作为客户,可以考虑使用静态类实现CheckPerson接口方便经常调用,也可以图方便使用匿名类:

```Java
        personList.printPersonAccordinTester(new PersonList.CheckPersons() {

            @Override
            public boolean test(Person p) {
                return p.getSex() == Person.Sex.MALE && p.getAge() >= 18
                        && p.getAge() <= 25;
            }

        });
```

Wo!看来我们找到了问题的通解,但是,我们还没有提到Lambda表达式吧?这不是本文的重点么?

在Eclipse中使用Lambda表达式

首先要声明的是Lambda表达式是Java8的新特性之一,如果你发现下文的代码无法编译,其实只是因为你没有安装最新的JDK罢了,下载连接

另外你还需要使Eclipse支持Java8,只需这样:官方教程

这样做之后,可能因为JRE为设为jre8所以无法编译,见下图:

eclipse build path

如果原来使用的是jre7的话,需要选择 Edit ,选择Alternate JRE:,再选择 Installed JREs... ,再选择jre8的安装目录就可以自动识别出来。

使用Lambda表达式

Lambda表达式最适合的地方大概就是实现只有一个抽象函数的接口。且看:

```Java
        personList.printPersonAccordinTester(p -> p.getSex()==Person.Sex.MALE && 
                p.getAge()>=18 && p.getAge()<=25 );
```

是不是很清晰? Lambda表达式的语法很简单变量声明(忽略类型)+表达式。当变量多于一个时,用 (v1,v2)表示,表达式多于一行时用{e1; e2; e3; return e4;}表示。

需要注意的是,当使用大括号后,括号内的全部内容就相当于替代了接口函数的全部内容,所以必要的 return 就不能省略了。

一个小优化

像我们的例子里定义的这个接口——输入参数,返回boolean——其实非常常用,Java在java.util.function中定义了一簇类似的函数,它们使用了泛型,足够我们使用了,这样就不必自己定义接口了。

注意这依然是Java8的新特性

于是乎 printPersonAccordinTester() 可以改写成这样: Java public void printPersonAccordinTester(Predicate<Person> tester) { for (Person p : persons) { if (tester.test(p)) { System.out.println(p.toString()); } } }

全部的java.util.function接口

让Lambda无处不在

让我们把 print方法更加定制化一些,不光能自定义选择,还可以自定义查询的内容,以及查询后做什么:

```Java
    public void dealTheList(Predicate<Person> tester,
            Function<Person, String> mapper, Consumer<String> dealer) {
        for (Person p : persons) {
            if (tester.test(p)) {
                String s = mapper.apply(p);
                dealer.accept(s);
            }
        }
    }
```

几乎就是一个 Select FROM WHERE 结构呀,那再看调用:

```Java
        personList.dealTheList(p -> p.getSex() == Person.Sex.FEMALE,
                p -> String.valueOf(p.getHeight()), s -> System.out.println(s));
```

条件:女性,查询:身高,处理:打印;

有没有启发性??

Java还支持stream(),专门提供一种串行的,更优雅的处理手段:

```Java
        personList.getPersons().stream()
                .filter(p -> p.getSex() == Person.Sex.FEMALE)
                .map(p -> p.getHeight()).forEach(h -> System.out.println(h));
```

关于聚合运算,还可以参考Aggregate Operations

小节

总而言之,在只需要单个函数,特别是这个函数还只需一句话就搞定的时候,使用Lambda表达式可以极大的简化繁琐的定义,使代码更清晰、更侧重逻辑而非结构。

算是一种编译型语言融合解释型语言有点的一种技巧吧。

谢谢阅读。

转载于:https://www.cnblogs.com/liuameng/p/3688888.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值