java lambda表达式 if_Java8 Lambda表达式的使用

参考

为什么要用Lambda表达式?

Lambda表达式可以让我们用较少的代码来实现更多的功能,尤其在Java这种相对来说比较“啰嗦”的语言中,是一把提高效率的利器。

演变过程

把官网上提供的demo拿过来

实体类

@Data

@AllArgsConstructorpublic classPerson {public enumSex {

MALE,FEMALE;

}privateString name;privateLocalDate birthday;privateSex gender;privateString emailAddress;privateInteger age;public voidprintPerson() {

System.out.println(this.toString());

}

}

需求

现在我们需要实现一个功能,按照某种标准,从Person的集合中,挑选出符合条件的对象。

写法一

/*** 第一种写法,所有的判断方法耦合在一起*/

public classPrintTest {//大于指定年龄即可

public static void printPersonOlderTan(List roster, intage) {for(Person person : roster) {if(person.getAge() >age) {

person.printPerson();

}

}

}//在某个年龄区间内

public static void printPersonWithinAgeRange (List roster, int low, inthigh) {for(Person person : roster) {if(low <= person.getAge() && person.getAge()

person.printPerson();

}

}

}

}

根据不同的要求写多个方法,不够灵活,重复代码较多。

写法二

上述代码存在的问题是,如果筛选的条件改变了,我们就需要写一个新的方法。

所以,思考一下我们可不可以把变化的部分单独拿出来。

public interfaceCheckPerson {booleantest(Person person);

}

public class CheckPersonEligibleForSelectiveService implementsCheckPerson{

@Overridepublic booleantest(Person person) {return person.getGender() == Person.Sex.MALE && person.getAge() >= 17 && person.getAge() <= 25;

}

}

/*** 将判断条件抽象成方法*/

public classPrintPerson {public static void printPerson(Listroster, CheckPerson tester) {for(Person person : roster) {if(tester.test(person)) {

person.printPerson();

}

}

}

将筛选条件封装成表示算法的类,当有新的需求下来的时候,可以根据不同的需要编写对应的类,实现 CheckPerson接口,重写test方法即可。

将不同的算法封装起来,实现同一个接口,利用java的多态,根据不同的需求指定对应的算法,这就是策略设计模式。

调用该方法

public classPrintPersonTest {public static voidmain(String[] args) {

Person person1= new Person("test1", null, Person.Sex.MALE, "qwert@gmail.com", 12);

Person person2= new Person("test2", null, Person.Sex.MALE, "qwert@gmail.com", 13);

Person person3= new Person("test3", null, Person.Sex.MALE, "qwert@gmail.com", 14);

List rosters =Arrays.asList(person1, person2, person3);//实例化算法类

CheckPersonEligibleForSelectiveService checkService = newCheckPersonEligibleForSelectiveService();

PrintPerson.printPerson(rosters, checkService)

}

}

写法三

有一种算法就需要定义一个类,如果说这个算法经常使用,倒还是值得的。

但如果这个算法只用一次,还要特地定义一个类,未免有些太不划算了。

所以这个时候就想起了jdk1.8之前就存在的匿名内部类。

public classPrintPersonTest {public static voidmain(String[] args) {

Person person1= new Person("test1", null, Person.Sex.MALE, "qwert@gmail.com", 12);

Person person2= new Person("test2", null, Person.Sex.MALE, "qwert@gmail.com", 13);

Person person3= new Person("test3", null, Person.Sex.MALE, "qwert@gmail.com", 14);

List rosters =Arrays.asList(person1, person2, person3);//匿名内部类

PrintPerson.printPerson(rosters, newCheckPerson() {

@Overridepublic booleantest(Person p) {return p.getGender() ==Person.Sex.MALE&& p.getAge() >= 18

&& p.getAge() <= 25;

}

});

}

}

写法四

Lambda表达式可以在匿名类的基础上,进一步简化写法。

public classPrintPersonTest {public static voidmain(String[] args) {

Person person1= new Person("test1", null, Person.Sex.MALE, "qwert@gmail.com", 12);

Person person2= new Person("test2", null, Person.Sex.MALE, "qwert@gmail.com", 13);

Person person3= new Person("test3", null, Person.Sex.MALE, "qwert@gmail.com", 14);

List rosters =Arrays.asList(person1, person2, person3);//lambda表达式

PrintPerson.printPerson(rosters, p -> p.getGender() ==Person.Sex.MALE&& p.getAge() >= 18

&& p.getAge() <= 25);

}

}

Lambda写法汇总

没有参数

public interfaceSayHello0 {voidsay();

}

/*** 函数没有参数*/

public classSayTest {public static voidmain(String[] args) {//写法一

SayHello0 sayHello0 = ()->{

System.out.println("hello");

};//写法二,可以省略大括号

SayHello0 sayHello01 = () -> System.out.println("hello2") ;//方法里面的内容多余一行的时候,必须要加大括号

SayHello0 sayHello02 = () ->{

System.out.println("hello3");

System.out.println("hello3");

};

}

}

一个参数

public interfaceSayHello1 {voidsay(String msg);

}

/*** 函数有1个参数*/

public classSayTest1 {public static voidmain(String[] args) {//写法一

SayHello1 sayHello1 = (msg)->{

System.out.println(msg);

};//写法二,简写

SayHello1 sayHello11 = msg ->System.out.println(msg);//写法三:再简写(这种写法的解释在后面)

SayHello1 sayHello12 =System.out::println;

}

}

两个及以上

public interfaceSayHello2 {voidsay(String name, String msg);

}

/*** 函数有2个参数*/

public classSayTest2 {public static voidmain(String[] args) {//多个参数时,小括号不能省略

SayHello2 sayHello2 = (name, msg) ->{

System.out.println("name" + "msg");

};

}

}

System.out::println

双冒号(::)也是1.8才有的运算符,用于lambda表达式中。

看一个demo

public classLambdaTest {public static voidmain(String[] args) {

Person person1= new Person("test1", null, Person.Sex.MALE, "qwert@gmail.com", 10);

Person person2= new Person("test2", null, Person.Sex.MALE, "qwert@gmail.com", 40);

Person person3= new Person("test3", null, Person.Sex.MALE, "qwert@gmail.com", 35);

Person person4= new Person("test4", null, Person.Sex.MALE, "qwert@gmail.com", 28);

Person person5= new Person("test5", null, Person.Sex.MALE, "qwert@gmail.com", 91);

List personList =Arrays.asList(person1, person2, person3, person4, person5);//personList.forEach(person -> System.out.println(person));

personList.forEach(System.out::println);

}

}

顺序输出集合中的所有元素

personList.forEach(person ->System.out.println(person));

personList.forEach(System.out::println);

这两种写法的效果是等价的,

先看forEach()方法需要的参数是什么

default void forEach(Consumer super T>action) {

Objects.requireNonNull(action);for (T t : this) {

action.accept(t);

}

}

Consumer是java8的内置函数式接口

@FunctionalInterfacepublic interface Consumer{voidaccept(T t);default Consumer andThen(Consumer super T>after) {

Objects.requireNonNull(after);return (T t) ->{ accept(t); after.accept(t); };

}

}

标注了@FunctionalInterface接口,符合函数式接口的规范。函数式接口要求接口只能有一个方法,这里的接口为啥会有两个呢?

第二个方法有个default关键字,所以不需要给他初始化,当你不实现他的时候,jvm会采用默认的实现方式。

。。。。。。

所以这个forEach方法是干嘛的

forEach遍历集合,把每一个元素都传给一个方法处理,而这个方法是用Consumer来接收的,所以必须符合Lambda表达式的规范。

所以

personList.forEach(System.out::println);

含义是,将personList里面的每一个元素都传给System.out这个对象的println方法,供这个方法消费(consumer)。

自定义一个类,来说明这么写的含义,可能会更好一点。

public classShowService {public voidshow(Person person) {

System.out.println(person);

}

}

测试类

public classLambdaTest {public static voidmain(String[] args) {

Person person1= new Person("test1", null, Person.Sex.MALE, "qwert@gmail.com", 10);

Person person2= new Person("test2", null, Person.Sex.MALE, "qwert@gmail.com", 40);

Person person3= new Person("test3", null, Person.Sex.MALE, "qwert@gmail.com", 35);

Person person4= new Person("test4", null, Person.Sex.MALE, "qwert@gmail.com", 28);

Person person5= new Person("test5", null, Person.Sex.MALE, "qwert@gmail.com", 91);

List personList =Arrays.asList(person1, person2, person3, person4, person5);ShowService showService= newShowService();

personList.forEach(showService::show);//或者把show改为静态方法 public static void show(Person person)//personList.forEach(ShowService::show);

}

}

至于forEach以及Stream等java8新特性,后面会陆续总结。

内置函数式接口

1.8新增的内置函数接口有很多,在java.util.function这个包下。

我们可以根据具体的需求,去使用不同的接口

例如

消费型接口(Consumer),有参数,返回值

public voidtest01(){//Consumer

Consumer consumer = (x) -> System.out.println("消费型接口" +x);//test

consumer.accept(100);

}

提供型接口(supplier),无参数,有返回值

public voidtest02(){

List list = new ArrayList<>();

List integers = Arrays.asList(1,2,3);

list.addAll(integers);//Supplier

Supplier supplier = () -> (int)(Math.random() * 10);

list.add(supplier.get());

System.out.println(supplier);for(Integer integer : list) {

System.out.println(integer);

}

}

函数型接口 Function,有参数,有返回值

public voidtest03(){//Function

String oldStr = "abc123456xyz";

Function function = (s) -> s.substring(1, s.length()-1);//test

System.out.println(function.apply(oldStr));

}

断言型接口 (Predicate),有参数,返回值为布尔型

public voidtest04(){//Predicate

Integer age = 35;

Predicate predicate = (i) -> i >= 35;if(predicate.test(age)){

System.out.println("你该退休了");

}else{

System.out.println("我觉得还OK啦");

}

}

实战

public classCompareTest {public static voidmain(String[] args) {

Person person1= new Person("test1", null, Person.Sex.MALE, "qwert@gmail.com", 10);

Person person2= new Person("test2", null, Person.Sex.MALE, "qwert@gmail.com", 40);

Person person3= new Person("test3", null, Person.Sex.MALE, "qwert@gmail.com", 35);

Person person4= new Person("test4", null, Person.Sex.MALE, "qwert@gmail.com", 28);

Person person5= new Person("test5", null, Person.Sex.MALE, "qwert@gmail.com", 91);//匿名内部类写法

List personList =Arrays.asList(person1, person2, person3, person4, person5);

Collections.sort(personList,new Comparator() {//从小到大排序

@Overridepublic intcompare(Person p1, Person p2) {return p1.getAge() -p2.getAge();

}

});

System.out.println(personList);//正则表达式写法

Collections.sort(personList, (p1, p2)->{return p1.getAge() -p2.getAge();

});//1.8以后的Comparator提供了专门的方法

Collections.sort(personList, Comparator.comparingInt(Person::getAge));//还可以这么用,BiFunction也是内置函数

BiFunction function= (p1, p2)-> p1.getAge() -p2.getAge();

function.apply(person1, person2);

}

}

如有错误,恳请批评指正!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值