lambda表达式、stream流、方法引用、mybatis-plus中的方法引用

本文介绍了Java中如何使用Lambda表达式简化多线程的代码,展示了Lambda的简洁语法,以及在StreamAPI中的应用,如forEach、filter、map等操作。同时,文章讲解了方法引用的概念,用于进一步简化代码,并提到了在MyBatisPlus中的LambdaQueryWrapper和LambdaUpdateWrapper的使用场景。
摘要由CSDN通过智能技术生成

入门体验

以使用Runnable接口开启多线程举例,使用lambda表达式可以简化代码写法

public class demo {
    public static void main(String[] args) {

        //匿名内部类写法
        Thread t0 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("唱,挑,rap");
            }
        });

        //lambda表达式写法,省略创建匿名对象过程,直接传递方法
        //(参数类型 参数名)->{
        //     代码块
        // }
        Thread t1 = new Thread(()->{
            System.out.println("唱,挑,rap");
        });
    }
}

lambda函数式编程思想

函数式编程思想强调做什么,不同面向对象思想,做什么都要以对象的方式进行操作

lambda表达式标准格式

(参数类型 参数名)->{
	//代码块。。。
}

lambda表达式简化格式

简化规则

  1. 小括号内参数类型可以省略
  2. 小括号内若有且只有一个参数,小括号可以省略
  3. 大括号内有且仅有一行代码,可以省略大括号、return及分号
    根据以上规则,可以将上面开启多线程代码继续简化
Thread t2 = new Thread(()-> System.out.println("唱,挑,rap"));

使用lambda表达式代替匿名内部类写法的前提

使用lambda表达式简化匿名内部类的写法的前提:被替代的原匿名内部类需要实现的接口中必须有且一个抽象方法(可以有其他的default默认方法),比如上面Runnable接口中就只有run一个抽象方法,这种接口就叫函数式接口,这种接口会被@FunctionalInterface注解标记,表示当前类可以使用lambda表达式简化调用写法

lambda表达式的表现形式

  1. 变量形式:变量的类型为函数接口时,可以使用lambda表达式。如
Runnable runnable = ()->System.out.println("唱,挑,rap");
  1. 参数形式:方法参数类型为函数接口时,可以使用lambda表达式,如
Thread t2 = new Thread(()-> System.out.println("唱,挑,rap"));
  1. 返回值形式:返回值类型为函数接口时,可以使用lambda表达式,如
public Runnable getRunnable(){
    return ()->System.out.println("唱,挑,rap");
}

stream流

特点:只能使用一次,针对同一stream流进行流处理后,之后就不能再使用该流进行处理了

获取stream流

  1. 获取Collection集合的stream流
    在这里插入图片描述

  2. 获取Map集合的stream流
    在这里插入图片描述
    这里通过map的key、value或key+value获取到的stream流后,就只能针对获取到的stream流进行加工

  3. 获取数组的stream流
    在这里插入图片描述

stream流常用api

stream流常用api可以分成两种:

  1. 终结方法:返回值不再是Stream接口类型的方法,所以调用完这类方法后不再支持链式调用,终结方法包括count和forEach
  2. 延迟方法:返回值仍然是stream接口类型的方法,所以之后仍然支持链式调用
    在这里插入图片描述
foreach

针对stream流中每个元素执行特定操作

foreach方法的定义

//返回值为void,属于终结操作
void forEach(Consumer<? super T> action);

foreach参数Consumer类的定义

//FunctionalInterface表示当前接口可以使用lambda表达式简化
@FunctionalInterface
public interface Consumer<T> {
	//accept方法中定义针对每个stream元素的遍历操作
    void accept(T t);
}

对比stream流foreach下的匿名内部类写法和lambda表达式写法

List<String> list = new ArrayList<>();
list.add("kunkun1");
list.add("kunkun2");
list.add("ikunkun4");
//获取list集合的stream流
Stream<String> stream = list.stream();
//stream流foreach+匿名内部类写法
stream.forEach(new Consumer<String>() {
    @Override
    public void accept(String name) {
        System.out.println(name);
    }
});
//stream流foreach+lambda表达式写法
stream.forEach(name->System.out.println(name));
count

统计stream流中元素个数

long count = stream.count();
filter

通过filter可以将一个流根据条件转换为另一个子流

filter方法的定义:

Stream<T> filter(Predicate<? super T> predicate);

参数Predicate类的定义:

//FunctionalInterface表示当前接口可以使用lambda表达式简化
@FunctionalInterface
public interface Predicate<T> {
	//参数t代表要过滤的每一个stream元素
	//返回值为boolean类型,当前元素在test方法中执行完成后若返回true说明满足过滤条件,进行将当前元素放入stream子流中,否则过滤掉
	boolean test(T t);
}

对比stream流filter下的匿名内部类写法和lambda表达式写法

List<String> list = new ArrayList<>();
list.add("kunkun1");
list.add("kunkun2");
list.add("ikunkun4");
//获取list集合的stream流
Stream<String> stream = list.stream();

//使用stream流过滤以k开头的名字
//stream流filter+匿名内部类写法
Stream<String> stream1 = stream.filter(new Predicate<String>() {
    @Override
    public boolean test(String name) {
        return name.startsWith("k");
    }
});
//stream流filter+lambda表达式写法
Stream<String> stream2 = stream.filter(name -> name.startsWith("k"));
limit

对stream流进行截取,只取前n个元素返回子流

List<String> list = new ArrayList<>();
list.add("kunkun1");
list.add("kunkun2");
list.add("ikunkun4");
//获取list集合的stream流
Stream<String> stream = list.stream();
//取前2个stream流元素生成子流返回
Stream<String> limit = stream.limit(2);
skip

跳过stream流中前n个元素,生成子流并返回

List<String> list = new ArrayList<>();
list.add("kunkun1");
list.add("kunkun2");
list.add("ikunkun4");
//获取list集合的stream流
Stream<String> stream = list.stream();
//跳过前2个stream流元素生成子流返回
Stream<String> skip= stream.skip(2);
map

将一个流中的元素映射到另一个流中,用于将一个类型的流转换为另一个类型的流,如

Stream<String>流转换为Stream<Long>

map方法的定义

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

map方法参数Function类的定义

//FunctionalInterface表示当前接口可以使用lambda表达式简化
@FunctionalInterface
public interface Function<T, R> {
	//将T类型的Stream流转换为R类型的Stream流
	//方法中定义具体的转换代码
    R apply(T t);

比较匿名内部类和lambda两种方式下将String的stream流转换为Long的stream流

 List<String> list = new ArrayList<>();
 list.add("1");
 list.add("2");
 list.add("3");
 //获取list集合的stream流
 Stream<String> stream = list.stream();
 
 //将String转换为Long类型的Stream流
 
 //stream流map+匿名内部类写法
 Stream<Long> objectStream = stream.map(new Function<String, Long>() {
     @Override
     public Long apply(String s) {
         return Long.valueOf(s);
     }
 });
 
 //stream流map+lambda写法
 Stream<Long> longStream = stream.map(s -> Long.valueOf(s));
concat

将两个stream流合并成一个流返回

List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
//获取list集合的stream流
Stream<String> stream1 = list.stream();
Stream<String> stream2 = list.stream();
//使用concat将两个流合并成一个
Stream<String> concat = Stream.concat(stream1, stream2);
reduce

用户对stream流中的元素进行累计运算

//累加
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(11);
list.add(12);
//参数1是累加的初始值,参数2是累加的方法引用
Integer result = list.stream().reduce(0, Integer::sum);
collect

用于收集stream流中的结果,将其装入list或set集合中

List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
//获取list集合的stream流
Stream<String> stream1 = list.stream();
Stream<String> stream2 = list.stream();
//使用concat将两个流合并成一个
Stream<String> concatStream = Stream.concat(stream1, stream2);
//收集到list集合中
List<String> collect = concatStream.collect(Collectors.toList());
//收集到set集合中
Set<String> collect1 = concatStream.collect(Collectors.toSet());

方法引用

方法引用是针对lambda表达式的进一步简化,当lambda表达式只是在调用某方法,就可使用方法引用进一步简化
在这里插入图片描述
这里以Person类举例

public class Person {
    String name;
    Integer age;

    /**
     * 比较两对象age的静态方法
     * @param o1
     * @param o2
     * @return
     */
    public static int compareByAge(Person o1,Person o2){
        return o1.getAge()- o2.getAge();
    }

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

静态方法引用举例

//需求:有三个Person对象,要放在一个数组中,并按年龄排序
Person[] people = {new Person("ikun1",10),new Person("ikun1",5),new Person("ikun1",20)};
//匿名内部类写法
Arrays.sort(people, new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge()-o2.getAge();
    }
});
//lambda表达式写法
Arrays.sort(people,((o1, o2) -> o1.getAge()- o2.getAge()));
//lambda+静态方法写法,这里的lambda表达式中只有调用某方法的动作,就能用方法引用简化
Arrays.sort(people,((o1, o2) -> Person.compareByAge(o1,o2)));
//lambda+静态方法引用写法,因为lambda表达式所接收的参数列表和静态方法需要接收的参数列表完全一致,所以能够简写,由jdk自动推导
Arrays.sort(people,Person::compareByAge);

静态方法引用格式:ClassName::StaticMethodName

成员方法引用举例

例1:

//需求:通过Supplier获取Person对象的名字
Person person = new Person("ikun",23);

//匿名内部类写法
Supplier supplier = new Supplier<String>() {
    @Override
    public String get() {
        return person.getName();
    }
};
//lambda写法
Supplier supplier1 = ()->person.getName();
//成员方法引用写法
Supplier supplier2 = person::getName;

例2:

//需求:遍历并打印出每个集合元素
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");

//lambda写法
list.forEach(i->System.out.println(i));

//lambda+实例方法引用写法,System.out返回的是PrintStream类的静态成员
PrintStream printStream = System.out;
list.forEach(printStream::println);
//上面的获取PrintStream对象的代码可以省略,以下面一行代替
list.forEach(System.out::println);

成员方法引用格式:objectName::MethodName

对象方法引用举例

//需求:利用BiPredicate函数式接口用于比较两个String,当两个字符串值相同就认为相等,而不是地址相同
String a = "ab";
String b = "bc";

//匿名内部类写法
BiPredicate<String,String> biPredicate = new BiPredicate<String, String>() {
    @Override
    public boolean test(String s, String s2) {
        return s.equals(s2);
    }
};

//lambda表达式写法
BiPredicate<String,String> biPredicate = (s1,s2)->s1.equals(s2);

//lambda表达式+对象方法引用写法
//若lambda表达式第一个参数是方法体中实例方法的调用者,且第二个参数是实例方法的参数,就能使用对象方法引用简化
BiPredicate<String,String> biPredicate = String::equals;

//调用biPredicate对象的test方法进行比较
System.out.println(biPredicate.test(a,b));

对象方法引用格式:ClassName::MethodName
注意与静态方法引用区分:ClassName::StaticMethodName

mybatis plus的lambda

LambdaQueryWrapper

用于构建查询条件,使用举例:

public class TestLog {
    @Autowired
    AdminMapper adminMapper;
    @Test
    public void textLog(){
        LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<>();

        //匿名内部类写法
        wrapper.like(new SFunction<Admin, Object>() {
            @Override
            public Object apply(Admin admin) {
                return admin.getUsername();
            }
        },"ikun");

        //lambda写法
        wrapper.like(admin -> admin.getUsername(),"ikun");

        //对象方法引用写法,底层会获取到Admin实体类username属性在数据库对应的列名,即查询数据库中Admin实体对应的表的username属性对应的字段值中包含ikun的数据
        wrapper.like(Admin::getUsername,"ikun");
        
        List<Admin> admins = adminMapper.selectList(wrapper);
    }
}

在开发中,可以这样使用:

wrapper.like(
	!StringUtils.isEmpty(username),
	Admin::getUsername,
	username
);
List<Admin> admins = adminMapper.selectList(wrapper);

第一个参数先判断查询条件是否存在,第二个参数通过方法引用指定列名,第三个参数指定查询条件

LambdaQueryWrapper支持链式编程,其中还有ge(大于查询条件)、le(小于查询条件)、eq(等于查询条件)等方法,用法和like一样

LambdaUpdateWrapper

用于构建修改条件,使用举例

LambdaUpdateWrapper<Admin> wrapper = new LambdaUpdateWrapper<>();
//先看oldUsername有没有值,有值就根据oldUsername的值匹配数据库中username字段,再看newUsername有没有值,有值就用其更新username字段
wrapper.eq(!StringUtils.isEmpty(oldUsername),Admin::getUsername,oldUsername)
        .set(!StringUtils.isEmpty(newUsername),Admin::getUsername,newUsername);

adminMapper.update(null,wrapper);

业务中的应用:
在这里插入图片描述

假设item.getCount() = 3,item.getSkuId() = 10,则上面的lambda表达式可以翻译为下面的sql,即从sku表中选择id为10的记录,判断记录中的stock字段-locked_stock字段的值是否大于3,若大于3就将locked_stock字段的值+3并返回true,否则不执行修改操作并返回false

update 
	sku 
set 
	locked_stock=locked_stok+3 
where 
	id = 10 and stock-locked_stock>=3
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值