Java 8 新特性之Lambda

558 阅读4分钟

简介

  • 面向对象是对数据进行处理,传递值
Peope people = new People(int i,String name);//最典型的构造器都是传值
public int sum(int a,int b){//传的是值,
  return a+b;
}
  • 函数式是一种行为,可以传递行为

  • Lambda的形状

(parm1,parm2,...) -> {
   方法体
}

为何需要Lambda表达式:

  • 在Java 8 之前,我们无法将函数作为参数传递给个方法,也无法声明返回一个函数的方法
  • 为了实现将函数作为参数,而加入了Lambda表达式
  • 在JavaScript中,函数参数是一个函数,返回值是另一个函数的情况是非常常见的;
  • JavaScript是一门非常典型的函数式语言
  • 经典的callback
$("button").click(function(){//click方法中传入的callback()方法
    $("p").hide(1000);
});

@FunctionalInterface详解

先从遍历这件事说起

public class TraverseTest {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6);
        for (int i = 0; i < list.size();i++){//远古时期
            System.out.println(list.get(i));
        }
        System.out.println("--------------------");
        for (Integer i : list){//近代--迭代器
            System.out.println(i);
        }
        System.out.println("---------------------");
        /*
        大多数(FunctionalInterface)功能接口仅意味着-功能接口,这严格意味着它们接受输入,
        进行一些计算并返回输出。(函数的本质)他们不应该修改任何状态。
        Consumer是例外,因为它不返回任何值。它的目的仅仅是修改某些状态。
         */
        list.forEach(new Consumer<Integer>() {//现代---forEach
            @Override
            public void accept(Integer integer) {
                int i = integer*integer;//副作用
                System.out.println(i);
            }
        });
        list.forEach(integer -> { System.out.println(integer);});
        list.forEach(System.out::println);//方法引用,引用System.out对象中的println方法实现accept方法
    }
}

要素察觉

何谓forEach

  • 点开源码瞧一瞧

image.png

  • 信息收集
    • forEach()Iterable接口中的方法,已经有默认实现
    • 功能:对迭代器中的每个元素进行操作
    • 参数:Consumer ,每个元素要执行的动作

何谓Consumer

  • 点看源码瞧一瞧

image.png

  • 信息收集
    • Consumer是一个接口,而且是一个functional interface
    • 里面有一个accept()方法
    • 还说与其他functional interface不一样,通过副作用进行操作
    • 之所以说不一样,是因为函数一般都有返回值,而Consumer没有返回值。如果它不通过副作用对数据进行改变和操作,那Consumer将没有任何意义,那要Consumer做什么。副作用其实就是指对数据的改变和操 作。
    • 副作用详解
    • 还使用了注解@FunctionalInterface

何谓@FunctionalInterface

  • 点开源码瞧一瞧

image.png

  • 信息收集
    • 是一个信息型注解,旨在告诉编译器,这是一个functional interface

    functional interfaces有人译为函数式接口

    • 函数式接口只能有一个抽象方法
    • 函数式接口可以有多个已经实现的默认方法,或者其他类已经实现的方法,如:Object类的toString()
      @FunctionalInterface
      public interface Function {
        void test();//只有一个抽象方法
        default void test1(){
          System.out.println(22222);
        }
        String toString();//已经被Object实现,该接口继承了它,因为Object是所有类的父类
      }
    
    • 函数式接口可以通过Lambda表达、方法引用或构造函数引用来实例化接口
    • 只要符合函数式接口的定义,无论是否使用注解@FunctionalInterface,编译器都可以识别

小结

1、Lambda表达式可以用来实现函数式接口

list.forEach(integer -> { System.out.println(integer);});//一般不需要指明参数类型
//因为List<Integer> 已经足够让编译器推断参数类型了

实现了Consumer接口

2、函数式接口只有一个抽象方法,实现了抽象方法也就实现了接口。所以当某个方法的参数是函数式接口时,只要传入方法的实现就可以了,方法的实现可以用Lambda表达式、方法引用(剽窃其他类的方法)。

3、虽然Lambda表达式是函数,但在Java中它是对象,因为它依附于特定的对象类型——函数式接口。因为它实现了对应函数式接口中的一个抽象方法,也可以说它实现了整个接口,Lambda表达式就是接口的实现类

小测试

@FunctionalInterface
public interface Function {
    void test();
}
class myTest {
    public void FunctionalInter(Function function){
        function.test();
        System.out.println("参数是函数式接口被实现了");
        System.out.println("----------------------");
    }
    public static void main(String[] args) {
         myTest myTest = new myTest();
         myTest.FunctionalInter(() -> System.out.println("表达式没有参数"));//间接调用test()
         Function functionInterface = () -> System.out.println("直接将表达式赋值给接口,接口就有了实现");
         functionInterface.test();//直接调用test()
    }
}

你可能会好奇

迭代器(Iterator)原理是什么?

方法引用是什么?

简要说明一下

  • 格式:
ClassName::Method
  • 含义
    • forEach为例
    list.forEach(System.out::println);
    
    • 因为forEach的参数是函数式接口Consumer,里面有抽象方法accept方法,只要实现了accept方法就实现了接口Consumer,任何实现?剽窃System.out中的println方法
    • 就形成accept = println,也就实现了accept,也就实现了Consumer接口