Lambda表达式使用解析

JDK8中能够添加了对于Lambda表达式支持,学习一下

1.Lambda表达式演进

假定有一个集合对象,现在要实现对于集合对象的过滤操作,过滤条件多变。例如

@Data
public class Dog {

    private Integer size;

    private String name;

    private Integer age;

    private Integer price;

    public Dog(Integer size, String name, Integer age, Integer price) {
        this.size = size;
        this.name = name;
        this.age = age;
        this.price = price;
    }
}

集合类

List<Dog> dogs = Arrays.asList(
            new Dog(1, "d1", 2, 5),
            new Dog(2, "d2", 3, 6),
            new Dog(3, "d3", 4, 2),
            new Dog(4, "d4", 1, 3)
    );

1.筛选出size>1的Dog集合

2.筛选出age>2的Dog集合.。。。

普通实现方式

编写两个方法,遍历集合依次判断,代码如下:

    //查询size大于1的Dog
    @Test
    List<Dog> selectDogsBySize(List<Dog> dogs){
        List<Dog> result = new ArrayList<>();
        for(Dog dog: dogs){
            if(dog.getSize()>1){
                result.add(dog);
            }
        }
        return result;
    }

    //查询age大于2的Dog
    @Test
    List<Dog> selectDogsByAge(List<Dog> dogs){
        List<Dog> result = new ArrayList<>();
        for(Dog dog: dogs){
            if(dog.getAge()>1){
                result.add(dog);
            }
        }
        return result;
    }

如果此时过滤条件发生变化,则需要重新编写函数来实现,并且大量函数代码逻辑都是相同的。

策略设计模式

将过滤条件抽离出来,设计成接口

public interface SelectStrategy<T> {

    boolean strategy(T t);

}

实现过滤函数逻辑,将选择策略传入

    //策略设计模式
    //通过某种策略来选择
    List<Dog> selectDogsByStrategy(List<Dog> dogs, SelectStrategy strategy){
        List<Dog> result = new ArrayList<>();
        for(Dog dog: dogs){
            if(strategy.strategy(dog)){
                result.add(dog);
            }
        }
        return result;
    }

对于每一种过滤需求,分别实现一种对应的策略

public class SizeSelectStrategy implements SelectStrategy<Dog> {
    @Override
    public boolean strategy(Dog dog) {
        return dog.getSize() > 2;
    }
}
public class AgeSelectStrategy implements SelectStrategy<Dog> {
    @Override
    public boolean strategy(Dog dog) {
        return dog.getSize() > 1;
    }
}

将具体策略传入业务逻辑函数,实现不同过滤需求

    @Test
    public void testStrategy(){
        selectDogsByStrategy(dogs, new AgeSelectStrategy());
        selectDogsByStrategy(dogs, new SizeSelectStrategy());
    }

如果继续有过滤需求,则可以实现不同的过滤策略来实现。假定过滤策略非常多,则会产生很多策略实现类。

匿名内部类

采用匿名内部类方式来实现具体策略

    //匿名内部类
    @Test
    public void testAnonymousInnerClass(){
        selectDogsByStrategy(dogs, new SelectStrategy<Dog>() {
            @Override
            public boolean strategy(Dog o) {
                return o.getSize() > 2;
            }
        });

        selectDogsByStrategy(dogs, new SelectStrategy<Dog>() {
            @Override
            public boolean strategy(Dog o) {
                return o.getAge() > 1;
            }
        });
    }

利用匿名内部类可以简化代码,但是匿名内部类大部分代码都是重复无用的。

Lambda表达式

    //lambda表达式
    @Test
    public void testLambda(){

        selectDogsByStrategy(dogs, (SelectStrategy<Dog>) o -> o.getAge() > 1);
        selectDogsByStrategy(dogs, (SelectStrategy<Dog>) o -> o.getSize() > 2);
    }

lambda表达式可以认为是对于匿名内部类简写的语法糖,其本质是实现策略设计模式,简化代码写法。

Stream API

    @Test
    public void testStream(){

        List<Dog> result = dogs.stream().filter(o -> o.getSize() > 2).collect(Collectors.toList());

        dogs.stream().filter(o -> o.getSize() > 2).forEach(System.out::println);

        dogs.stream().map(Dog::getName).limit(2).forEach(System.out::println);
    }

Stream API提供了对于集合的强大编程简化能力。


2.Lambda表达式语法

函数式接口:接口中只有一个抽象方法,可以使用@FunctionalInterface注解来标注

@FunctionalInterface
public interface FunctionInter<T> {

    T func(T t);
}

其基本格式如下:

(参数列表) ->{lambda体}

参数列表对应接口中抽象方法的参数,lambda对应抽象方法的逻辑实现。

对于抽象方法的参数以及返回值可以分为以下情况:

1.无参数,无返回值

//抽象方法   无参数  无返回值  ()->
Runnable r2 = () -> System.out.println("lllllllll");
r2.run();

2.一个参数,无返回值

Consumer<String> con = (s) -> System.out.println(s);
con.accept("conconcon");

3.若只有一个参数,左边小括号可以不写

Consumer<String> con2 = s -> System.out.println(s);
con2.accept("conconcon");

4.两个参数,有返回值,lambda体中有多行语句,则需要使用大括号

Comparator<Integer> com = (x, y) -> {
      System.out.println("com");
      return Integer.compare(x, y);
};

5.lambda体中只有一条语句,则return和大括号可以不写

Comparator<Integer> com2 = (x, y) -> Integer.compare(x, y);

6.lambda表达式参数类型可以不写,JVM编译器可以根据上下文推断出参数类型 类型推断

Comparator<Integer> com3 = (Integer x, Integer y) -> Integer.compare(x, y);

 


3.Lambda表达式示例

新建一个线程

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("t1");
    }
}).start();

new Thread(() -> System.out.println("t2")).start();

利用lambda表达式实现策略

@FunctionalInterface
public interface FunctionInter<T> {

    T func(T t);
}
public Integer doFunc (Integer num, FunctionInter<Integer> functionInter){
    return functionInter.func(num);
}
System.out.println(doFunc(1, x -> x + x));
System.out.println(doFunc(1, x -> x * x));
System.out.println(doFunc(1, x -> x + 100));

排序比较器实现

Collections.sort(dogs, (d1, d2) ->{
    if(d1.getName().equals(d2.getName())){
        return d1.getName().compareTo(d2.getName());
    }else{
        return Integer.compare(d1.getSize(), d2.getSize());
    }
});
dogs.stream().forEach(System.out::println);

4.java8核心函数式接口

//Consumer 消费性接口
//Supplier 供给型接口
//Function<T,R> 函数型接口
//predicate<T>  断言型接口

1.Consumer接口  对应一个参数  无返回值

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

 

public void buy(double money, Consumer<Double> con){
    con.accept(money);
}
buy(100, (m) -> System.out.println(m));

2.Supplier接口  无参数  有返回值

 

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

 

public List<Integer> produce(int num, Supplier<Integer> supplier){
    List<Integer> result = new ArrayList<>();
    for(int i=0; i<num; i++){
        result.add(supplier.get());
    }
    return result;
}
Random r = new Random();
r.setSeed(new Date().getTime());
produce(10, () -> r.nextInt() * 100).stream().forEach(System.out::println);

3.Function接口 一个参数 一个返回值

 

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

 

public String dealString(String str, Function<String, String> function){
    return function.apply(str);
}
dealString("aDcbF", (s) -> s.toLowerCase());
dealString("aDcbF", (s) -> s.toUpperCase());

4.Predicate接口 一个参数  返回true或false

 

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
public List<String> addStringToList(List<String> ll, Predicate<String> predicate){
    List<String> result = new ArrayList<>();
    for(String s : ll){
        if(predicate.test(s)){
            result.add(s);
        }
    }
    return result;
}
addStringToList(Arrays.asList("asc","sdcd","dssfdsf"), (s) -> s.startsWith("a"));

5.方法引用与构造器引用

如果lambda体中要实现的方法在已有的类中已经有实现,则可以使用方法引用

要求 函数式接口和已有方法具有相同的参数列表和返回值

其实现形式有   对象::实例方法名   类::静态方法名  类::实例方法名

//对象::实例方法名
Consumer<String> con = (x) -> System.out.println(x);

PrintStream ps = System.out;
Consumer<String> con2 = ps :: println;

Consumer<String> con3 = System.out::println;

Dog dog = new Dog();
Supplier<String> supplier = () -> dog.getName();

Supplier<String> supplier1 = dog::getName;
//类::静态方法名
Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y);

Comparator<Integer> comparator2 = Integer::compare;
//类::实例方法名
//第一个参数是方法调用者,第二个参数是方法参数
BiPredicate<String, String> biPredicate = (s1, s2) -> s1.equals(s2);

BiPredicate<String, String> biPredicate2 = String::equals;

构造器引用

Dog对象

@Data
public class Dog {

    private Integer size;

    private String name;

    private Integer age;

    private Integer price;

    public Dog(){}

    public Dog(String name){
        this.name = name;
    }

    public Dog(Integer size, Integer age){
        this.size = size;
        this.age = age;
    }

    public Dog(Integer size, String name, Integer age, Integer price) {
        this.size = size;
        this.name = name;
        this.age = age;
        this.price = price;
    }
}
//根据参数自动匹配相应的构造器
Function<String, Dog> function = (x) -> new Dog(x);
Function<String, Dog> function2 = Dog::new;

BiFunction<Integer, Integer, Dog> fun = (x, y) -> new Dog(x, y);
BiFunction<Integer, Integer, Dog> fun2 = Dog::new;

数组引用

Function<Integer, String[]> fun3 = (x) -> new String[x];
Function<Integer, String[]> fun4 = String[]::new;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值