-
场景例子
假设现在是一个万人选对象的现场。活动方的后台屯了一堆资源,男男女女老老少少都有,上台的嘉宾可以说出自己的要求,然后台上出现符合你要求的人,介绍下自己。万人选妃,吃鸡。
人类定义:package jdk8.lambada.case1; import java.time.LocalDate; public class Person { /** * 姓名,我们是实名制的相亲活动,必须是真实姓名 */ String name; /** * 出生年月,年龄很重要啊 */ LocalDate birthday; /** * 这也很重要啊 */ Sex gender; /** * 描述下呗 */ String describe; public String getDescribe() { return describe; } public void setDescribe(String describe) { this.describe = describe; } public int getAge() { return LocalDate.now().compareTo(birthday); } public void printPerson() { } public enum Sex { MALE, FEMALE } public Person(String name, LocalDate birthday, Sex gender, String describe) { this.name = name; this.birthday = birthday; this.gender = gender; this.describe = describe; } public Person() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public LocalDate getBirthday() { return birthday; } public void setBirthday(LocalDate birthday) { this.birthday = birthday; } public Sex getGender() { return gender; } public void setGender(Sex gender) { this.gender = gender; } public static int compareByAge(Person a, Person b) { return a.birthday.compareTo(b.birthday); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", birthday=" + birthday + ", gender=" + gender + ", describe='" + describe + '\'' + '}'; } }
我们的资源是充分的,少资源就new一个。
public static List<Person> createSource(){ //我们先初始化后台资源,程序员缺啥new啥 List<Person> list = new ArrayList<>(); //先来一群女的 list.add(new Person("韩梅梅", LocalDate.of(1990, 1, 2), Person.Sex.FEMALE, "人美成绩好,英语专家")); list.add(new Person("lucy", LocalDate.of(1994, 8, 20), Person.Sex.FEMALE, "来自英国,lily的姐妹")); list.add(new Person("翠花", LocalDate.of(1980, 1, 7), Person.Sex.FEMALE, "做的酸菜很好吃")); list.add(new Person("李倩倩", LocalDate.of(1992, 8, 2), Person.Sex.FEMALE,"护士妹妹")); list.add(new Person("慕容玉", LocalDate.of(1988, 1, 7), Person.Sex.FEMALE, "御姐气质")); list.add(new Person("李倩倩", LocalDate.of(1992, 8, 2), Person.Sex.FEMALE, "家里很有钱")); list.add(new Person("罗玉凤", LocalDate.of(1985, 1, 2), Person.Sex.FEMALE, "我只要冠希哥")); list.add(new Person("李小璐", LocalDate.of(1985, 1, 2), Person.Sex.FEMALE, "喜欢做头发")); //再来一群男的 list.add(new Person("陈冠希", LocalDate.of(1980, 1, 2), Person.Sex.MALE, "机不离身")); list.add(new Person("慕容复", LocalDate.of(1960, 10, 2), Person.Sex.MALE, "富N代")); list.add(new Person("张三", LocalDate.of(1990, 1, 2), Person.Sex.MALE, "无名小卒")); list.add(new Person("李四", LocalDate.of(1980, 1, 2), Person.Sex.MALE, "张三同村村长家的")); list.add(new Person("史泰龙", LocalDate.of(1960, 1, 2), Person.Sex.MALE, "很能打")); return list; }
一号嘉宾:
大龄未婚男,急着结婚,要求简单,只要是女女就行。很简单的愿望,实现也很简单。
实现:/** * 选个简单对象就好,没啥要求 * @param personList */ public static void chooseSimpleObject(List<Person> personList){ for (Person person : personList) { if (person.getGender() == Person.Sex.FEMALE) { System.out.println(person); } } } // main 函数 public static void main(String[] args) { List<Person> personList = createSource(); chooseSimpleObject(personList); } /** 输出: Person{name='韩梅梅', birthday=1990-01-02, gender=FEMALE, describe='人美成绩好,英语专家'} Person{name='lucy', birthday=1994-08-20, gender=FEMALE, describe='来自英国,lily的姐妹'} Person{name='翠花', birthday=1980-01-07, gender=FEMALE, describe='做的酸菜很好吃'} Person{name='李倩倩', birthday=1992-08-02, gender=FEMALE, describe='护士妹妹'} Person{name='慕容玉', birthday=1988-01-07, gender=FEMALE, describe='御姐气质'} Person{name='李倩倩', birthday=1992-08-02, gender=FEMALE, describe='家里很有钱'} Person{name='罗玉凤', birthday=1985-01-02, gender=FEMALE, describe='我只要冠希哥'} Person{name='李小璐', birthday=1985-01-02, gender=FEMALE, describe='喜欢做头发'} */
我们写了一个chooseSimpleObject方法,方法很简单。一号嘉宾的要求得到满足,但是可以没有牵手成功,很遗憾。
二号嘉宾:
老子有钱,要找就找个年轻的,年龄在18-25。这个要求,也容易满足。各位嫖客,呸呸呸,各位看官请看:/** * 选择个漂亮的 * @param personList */ public static void chooseYongObject(List<Person> personList) { for (Person person : personList) { if (person.getGender() == Person.Sex.FEMALE && person.getAge() <= 25 && person.getAge() >= 18) { System.out.println(person); } } } //main函数 public static void main(String[] args) { List<Person> personList = createSource(); chooseYongObject(personList); } /**输出: Person{name='lucy', birthday=1994-08-20, gender=FEMALE, describe='来自英国,lily的姐妹'} */
三号嘉宾:
凤姐上来了,我只要冠希哥。这个。。。。好吧,给你冠希哥。接好了。/** * 只要陈冠希 * @param personList */ public static void chooseChenguanxi(List<Person> personList) { for (Person person : personList) { if ("陈冠希".equals(person.getName())) { System.out.println(person); } } } //main 函数 public static void main(String[] args) { List<Person> personList = createSource(); chooseChenguanxi(personList); } /**输出: Person{name='陈冠希', birthday=1980-01-02, gender=MALE, describe='机不离身'} */
从上面三个例子中,我们发现,每个人的择偶标准都不一样,但是流程都是一样的,都是for-if-then结构,换句话说,if的条件是变的。那么这个变动的部分能不能封装起来,以变量的形式传入目标方法呢?答案是当然行的。我们定义一个公共的择偶方法
chooseObjectByCondition()
,如下:/** * 择偶方法 * @param personList * @param chooseCondition */ public static void chooseObjectByCondition(List<Person> personList, ChooseCondition chooseCondition) { for (Person person : personList) { if (chooseCondition.isRightObject(person)) { System.out.println(person); } } }
接口ChooseCondition
package jdk8.lambada.case1; public interface ChooseCondition { /** * 是那个人吗? * @param person * @return */ boolean isRightObject(Person person); }
接口ChooseCondition的实现,满足第二个嘉宾的条件实现。
class ChooseYong implements ChooseCondition{ @Override public boolean isRightObject(Person person) { return person.getGender() == Person.Sex.FEMALE && person.getAge() <= 25 && person.getAge() >= 18; } }
在main方法调用
public static void main(String[] args) { List<Person> personList = createSource(); chooseObjectByCondition(personList, new ChooseYong()); }
我们用了一个接口,把if条件抽象成一个方法,在目标方法接受接口的形参,调用的时候根据不同人的择偶标准实例化不同的接口实现类。显然,这种方法还是有瑕疵的,注意这里有个ChooseCondition的实现,如果人越多,像这种实现类就会越来越多,项目就会越来越臃肿。所以,下一步,去掉接口实现类,用匿名内部类(Anonymous class)优化下。
public static void main(String[] args) { List<Person> personList = createSource(); chooseObjectByCondition(personList, new ChooseCondition() { @Override public boolean isRightObject(Person person) { return person.getGender() == Person.Sex.FEMALE && person.getAge() <= 25 && person.getAge() >= 18; } }); }
嗯,代码减少了很多。还能不能再把接口干掉呢?额,如果是JDK8以下的话,是不行的,但是JDK8给我们预置了很多接口函数。接口函数,我们待会介绍。先把上面的自定义接口干掉。
修改main()
方法入参为JDK8预置判断接口Predicate/** * 择偶方法 * @param personList * @param predicate */ public static void chooseObjectByCondition(List<Person> personList, Predicate predicate) { for (Person person : personList) { if (predicate.test(person)) { System.out.println(person); } } }
main()
函数做对应修改public static void main(String[] args) { List<Person> personList = createSource(); chooseObjectByCondition(personList, new Predicate<Person>() { @Override public boolean test(Person person) { return person.getGender() == Person.Sex.FEMALE && person.getAge() <= 25 && person.getAge() >= 18; } }); }
又精简了一步,好哈皮。其实,这离我们今天要说得lambada表达式只有一步之遥了,下面我们就跨出这一步,走起,对main函数再改造下。
public static void main(String[] args) { List<Person> personList = createSource(); chooseObjectByCondition(personList, person -> person.getGender() == Person.Sex.FEMALE && person.getAge() <= 25 && person.getAge() >= 18); }
到此为止,lambada表达式闪亮登场,我们再把上面的业务完善下,完全用jdk8的特性替换。
/** * 择偶,符合条件的再干些事情 * @param personList * @param predicate * @param function * @param consumer */ public static void chooseObjectByConditionDoSomeThing(List<Person> personList, Predicate<Person> predicate, Function<Person, String> function, Consumer<String> consumer) { for (Person person : personList) { if (predicate.test(person)) { String s = function.apply(person); consumer.accept(s); } } }
public static void main(String[] args) { List<Person> personList = createSource(); chooseObjectByConditionDoSomeThing(personList, person -> { return person.getGender() == Person.Sex.FEMALE && person.getAge() <= 25 && person.getAge() >= 18; }, Person::getName, System.out::println); }
再上个终极版本
public static void main(String[] args) { List<Person> personList = createSource(); personList.stream().filter(person -> person.getGender() == Sex.FEMALE && person.getAge() <= 25 && person.getAge() >= 18).map(Person::getName).forEach(System.out::println); }
-
什么是Lambda表达式?
Lambda表达式可以封装单个行为单元,然后传给其他代码。
语法:p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25
分为三部分:
- 入参,p是省略后的格式,完整的格式为(Person p),入参的类型可以省略。只有一个入参时,小括号也可以省略。当有多个入参时,以逗号隔开,如(p1,p2);
- ->,箭头;
- 函数体,表达式的处理逻辑。多行代码时需要加上大括号,只有一行代码时大括号可以省略,表达式有返回值时,
return
关键字是可选。