常用函数接口及使用

根据以上的例子,我们定义的SkuPredicate和FileConsumer这两个接口的传参明确指定了对象(Sku和String),这样不够泛化,在JDK8中提供了一些泛化的接口,如下

接口 参数 返回类型 描述
Predicate<T> T boolean 用于判别一个对象。比如求一个人是否为男性。
Consumer<T> T void 用于接收一个对象进行处理但没有返回,比如接收一个人并打印他的名字
Function<T, R> T R 转换一个对象为不同类型的对象
Supplier<T> None T 提供一个对象
UnaryOperator<T> T T 接收对象并返回同类型的对象
BinaryOperater<T> (T, T) T 接收两个同类型的对象,并返回一个原类型对象

函数式接口示例:

image-20210714125122670

rt.jar预制了很多类似的函数式接口

image-20210714125211028

从上面看到,为基础类型提供了很多函数式接口,供我们选择,选择基础类型函数式接口的好处是不会装箱拆箱,提升了很大性能提升。在上面看到的Function函数式接口,就是一种很泛化的接口,适合处理非基础类型的接口。

方法引用

有时我们会看到如下的代码

1
2
3
4
5
Optional.ofNullable(cartSkuList)
.map(List::stream)
.orElseGet(Stream::empty)
.sorted(Comparator.comparing(Sku::getTotalNum))
.forEach(resultSluList::add);

看到代码中有很多的::,这是什么语法呢?是方法引用

调用特定方法的Lambda表达式的一种快捷写法,可以让你重复使用现有的方法定义,并像Lambda表达式一样传递他们。

Sku :: getSkuPrice
目标引用 双冒号分隔符 方法名

指向静态方法的方法引用

1
2
3
4
5
6
7
8
/**
* (args) -> ClassName.staticMethod(args);
* ClassName::staticMethod;
*/
public void test1() {
Consumer<String> consumer1 = (String number) -> Integer.parseInt(number);
Consumer<String> consumer2 = Integer::parseInt;
}

指向任意类型实例方法的方法引用

1
2
3
4
5
6
7
8
/**
* (args) -> args.instanceMethod;
* ClassName::instanceMethod;
*/
public void test2() {
Consumer<String> consumer1 = (String str) -> str.length();
Consumer<String> consumer2 = String::length;
}

指向现有对象的实例方法的方法引用

1
2
3
4
5
6
7
8
9
/**
* (args) -> object.instanceMethod(args);
* object::instanceMethod
*/
public void test3() {
StringBuilder stringBuilder = new StringBuilder();
Consumer<String> consumer1 = (String str) -> stringBuilder.append(str);
Consumer<String> consumer2 = stringBuilder::append;
}

方法引用精讲

Lambda表达式的由来

使用实体类代表判断逻辑

1
2
// 2. 过滤商品总价大于2000的商品
List<Sku> skus = CartService.filterSkus(cartSKuList, new SkuTotalPricePredicate());

使用匿名类代表判断逻辑

1
2
3
4
5
6
7
8
// 2. 过滤商品单价大于1000的商品,使用匿名类调用
List<Sku> skus = CartService.filterSkus(cartSKuList,
new SkuPredicate() {
@Override
public boolean test(Sku sku) {
return sku.getSkuPrice() > 1000;
}
});

使用Lambda表达式代表判断逻辑

1
2
3
// 2. 过滤商品单价大于1000的商品,使用lambda表达式一句实现
List<Sku> skus = CartService.filterSkus(cartSKuList,
(Sku sku) -> sku.getSkuPrice() > 1000);

方法引用的由来

使用方法引用代表判断逻辑

1
2
3
4
5
6
7
8
9
public class Sku {
// 价格比较方法
public Boolean comparePrice() {
return this.skuPrice > 1000;
}
}

// Lambda表达式引用
List<Sku> result = CartService.filterSkus(cartSkuList, Sku::comparePrice);

方法引用的作用

  • 方法引用是用来直接访问类或者实例的已存在的方法或者构造方法。

方法引用的表达形式

  • 目标引用::方法名

方法引用分类

  • 四种方法引用类型
方法引用类型 表示形式
指向静态方法 Class::staticMethod
指向现有对象的实例方法 object::instanceMethod
执行任意类型的实例方法 Class::instanceMethod
指向构造方法 Class::new
  • 实战案例:四种方法引用的使用场景及区别

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    package com.java.example;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Optional;

    /**
    * 实战案例:四种方法引用的使用场景及区别
    *
    * @author jingLv
    * @date 2020/10/27
    */
    public class MethodReferenceTest {

    static class Sku {
    private String skuName;
    private Integer skuPrice;

    public Integer getSkuPrice() {
    return skuPrice;
    }

    // 静态方法
    public static int staticComparePrice(Sku sku1, Sku sku2) {
    return sku1.getSkuPrice() - sku2.getSkuPrice();
    }

    // 实例方法
    public int instanceComparePrice(Sku sku) {
    return this.getSkuPrice() - sku.getSkuPrice();
    }
    }

    class PriceComparator {
    // 实例方法
    public int instanceComparePrice(Sku sku1, Sku sku2) {
    return sku1.getSkuPrice() - sku2.getSkuPrice();
    }
    }

    public void test() {
    List<Sku> skuList = new ArrayList<>();
    // 进行单价排序
    skuList.sort((sku1, sku2) -> sku1.getSkuPrice() - sku2.getSkuPrice());

    // 在Sku中写一个静态方法与排序的逻辑一直则可以替换方法引用
    // 类名::静态方法名
    skuList.sort(Sku::staticComparePrice);
    // 类名::静态方法名的展开形式
    skuList.sort((Sku sku1, Sku sku2) -> {
    return Sku.staticComparePrice(sku1, sku2);
    });

    PriceComparator priceComparator = new PriceComparator();
    // 对象::实例方法名
    skuList.sort(priceComparator::instanceComparePrice);
    // 对象::实例方法名的展开形式
    skuList.sort((Sku sku1, Sku sku2) -> {
    return priceComparator.instanceComparePrice(sku1, sku2);
    });

    // 类名::实例方法名
    skuList.sort(Sku::instanceComparePrice);
    // 类名::实例方法名的展开形式
    skuList.sort((Sku object, Sku sku) -> {
    return object.instanceComparePrice(sku);
    });

    // 构造方法,skuList防空处理
    Optional.ofNullable(skuList).orElseGet(ArrayList::new);
    }
    }