Java8学习记录(一)——Lambda表达式

这两天看了《Java8实战》,做一下记录。

目录

一、行为参数化:

1.什么是行为参数化:

二、函数式接口:

1.概念:

三、Lambda表达式:

四、方法引用(注意点):

1.静态方法引用:

2.实例方法引用(重点来了):

①任意类型的实例方法引用: 

②现有对象的实例方法引用:

3.构造方法引用:


一、行为参数化:

1.什么是行为参数化:

1. 你说:我要所有重量为 50g 的苹果。管理员调用 findByWeight(int weight) 拿给你。

2. 你又说你要红色的所有苹果,管理员调用 findByColor(String color) 帮你找到。

3. 这时你又要重量为 50g 并且为红色的所有苹果,管理员:???。

4.现在只好请来程序员带哥,修改程序加上一个 findByWeightAndColor(int weight, String color)。

   有了 findByWeightAndColor 还要 findByWeight 和 findByColor,这就打破了Don't Repeat Yourself(不要重复你自己)的软件工程原则。于是考虑将这两个需求结合成一个方法。用两个 boolean 参来控制筛选条件,具体逻辑就不写了。

findByWeightAndColor(int weight, boolean useWeight, String color, boolean useColor
);

   这样写不但臃肿,而且如果需要刷选大于50克的苹果,那还得重新写一个方法。这是不能接收的。

以上例子是把值作为参数进行查找,对于不同需求需要写不同的方法,每种查找方式都需要写一个方法,这显然是不合理的。这时程序员带哥就想到,为什么不能只写一个方法,把需求也就是行为当做参数进行传递呢?

 

①此时,只需要写一个过滤器接口,里面写一个抽象过滤方法,而过滤条件自己定义就好了。

public interface AppleFilter {
   boolean filter(Apple apple);
}

②把自己写好的过滤条件 appleFilter 当做参数传进去。

pubic List<Apple> getApple(List<Apple> list, AppleFilter appleFilter){
    if (appleFilter.filter(apple)){
        ......
    }
    .....
}

③自定义过滤重量 >50 克且颜色为 red 过滤器。这不就是熟悉的匿名内部类吗(匿名内部类需要注意这几点)。

List<Apple> list1 = obj.getApple(list, new AppleFilter() {
    @Override
    public boolean filter(Apple apple) {
        if ("red".equals(apple.getColor) && apple.getWeight()>50){
            return true;
        }
        return false;
    }
});

以上就是行为参数化。

 

二、函数式接口:

1.概念:

① 如果一个接口只有一个抽象方法,那它就是函数式接口。(注意是抽象方法)

② 加了@FunctionalInterface 注解的接口就是函数式接口,但得符合条件①才行。

这样看来,上面定义的过滤器接口就是一个函数式接口

public interface AppleFilter {
   boolean filter(Apple apple);
}

Java库中也有定义好的函数式接口:

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

 

三、Lambda表达式:

现在就要引出 Lambda表达式了:

1.Lambda 必须依附在函数式接口上。

2.Lambda 实际上是一种语法糖。

List<Apple> list1 = obj.getApple(list, new AppleFilter() {
    @Override
    public boolean filter(Apple apple) {
        .......
    }
});

对于上文的代码,可以用 Lambda 表达式来写。

List<Apple> list1 = c.getApple(list,
    (Apple apple) -> apple.getWeight()>50 && "red".equals(apple.getColor()));

也可以这样写:

AppleFilter appleFilter = apple -> "red".equals(apple.getColor()) && apple.getWeight()>50;
List<Apple> list1 = obj.getApple(list, appleFilter);

再如,新建一个线程执行打印:

new Thread(()-> sout("hello world")).start();

Lambda表达式必须通过上下文进行推断,推断过程:

 

四、方法引用(注意点):

1.静态方法引用:

Function<String, Integer> function = s -> Integer.parseInt(s);
                         ↓
Function<String, Integer> function = Integer::parseInt;
int num = function.apply("123");

2.实例方法引用(重点来了):

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

Function<String, Integer> function = s -> s.length();
//可以这样写
Function<String, Integer> function = String::length;
//参数写进去
function.apply("qwe");

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

public int getValue(int num) {
    return this.hashCode() - num;
}

Apple apple = new Apple();
Function<Integer, Integer> function = num -> apple.getValue(num);
//可以写成这样
Function<Integer, Integer> function1 = apple1::getValue;

System.out.println((apple.hashCode()-3) == function.apply(3));//true

这究竟是什么意思?我比较浅显推断应该是这样(如果不对请指正):

①任意类型的实例方法引用: 

                           Lambda:( arg0, rest ) -> arg0 .method ( rest )       对应上面代码 s -> s.length();

               方法引用: ClassName :: method            对应上面代码 String::length;

:: 前面的类型和后面的方法名可以用来匹配参数,返回值就是 :: 后面的方法的返回值,通过 :: 前面的类型可以创建一个对象 obj。如上面代码 String::length,通过String可以创建一个String对象,后面的 length() 不需要参数。所以 function.apply("qwe"), "qwe"就是传入的对象;返回值就是由 obj.length() 计算所得。

 

现有对象的实例方法引用:

                          Lambda: (args) -> expr . method(args)       对应上面代码 function = num -> apple.getValue(num);

                          方法引用: expr :: method       对应上面代码  function = apple1 :: getValue;

function.apply(3)。:: 前面已经有具体对象,所以直接 apple1.getValue(3) 获得返回值。

 

再看一个究极例子加深理解(参考文章):

public interface FunctionInterface {
    public int calculate(Bean1 bean1, Bean2 bean2);
}
public class Bean1 {
    public void expect1(Bean1 bean1) {}

    public int expect2(Bean2 bean2){
        return this.hashCode() - bean2.hashCode();
    }

    public void test1(FunctionInterface i) {}
}
public class Bean2 {
    public void expect1(Bean1 bean1) {}

    public int expect2(Bean2 bean2) {}

    public void test1(FunctionInterface i) {}
}

测试代码:

public static void main(String[] args) {
    FunctionInterface interface1 = (Bean1 bean1, Bean2 bean2) -> bean1.hashCode() - bean2.hashCode();
    FunctionInterface interface2 = Bean1::expect2;

    Bean1 bean1 = new Bean1();
    Bean2 bean2 = new Bean2();

    //计算结果是一样的
    System.out.println(bean1.hashCode() - bean2.hashCode());
    System.out.println(interface1.calculate(bean1, bean2));//1.
    System.out.println(interface2.calculate(bean1, bean2));//2.
}

1式:正宗的 Lambda 表达式,不用多说。

2式:这个就有意思了,Bean1 :: expect2。根据上文分析,:: 生成Bean1类型的一个对象,调用 expect2 方法,expect2 方法中有一个 Bean2 类型的参数,要想执行 calculate 方法,那么到目前还缺一个参数。其实并不缺,也就是说省略了Bean1类型的参数bean1,lambda 就可以使用:: 前导的Bean1构建一个对象,作为第一个参数。

 

3.构造方法引用:

Supplier supplier = () -> new Apple();
            ↓
Supplier supplier = Apple::new;

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值