欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

深入理解lambda表达式与@FunctionalInterface函数式接口(一)

程序员文章站 2023-02-14 23:12:36
一、集合遍历与Lambda表达式 引入 二、 @FunctionalInterface函数式接口与Lambda表达式 1、概念 2、 函数式接口的区分 3、函数式接口的实例化方式 4、函数式接口中的默认方法 5、总结与思考 三、函数式接口实例化 之 Lambda表达式 四、在排序过程中 Lambda ......

一、集合遍历与lambda表达式 引入

package com.java.design.java8;

import org.junit.test;
import org.junit.runner.runwith;
import org.springframework.boot.test.context.springboottest;
import org.springframework.test.context.junit4.springrunner;

import java.util.*;
import java.util.function.consumer;

/**
 * @author 陈杨
 */
@runwith(springrunner.class)
@springboottest
public class ergodiclist {


    @test
    public void testergodiclist() {

        //  直接构造集合对象 保证了集合size>0
        list<integer> list = arrays.aslist(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);


        system.out.println("---------------------------传统for循环--------------------\n");
        for (int i = 0; i < list.size(); i++) {
            system.out.println(list.get(i));
        }

        system.out.println("---------------------------增强for循环--------------------\n");
        for (integer i : list) {
            system.out.println(i);
        }

        system.out.println("---------------------------迭代器-------------------------\n");

        iterator<integer> iterator = list.iterator();
        while (iterator.hasnext()) {
            integer integer = iterator.next();
            system.out.println(integer);
        }


        system.out.println("---------------------------foreach------------------------\n");
        list.foreach(new consumer<integer>() {
            @override
            public void accept(integer integer) {
                system.out.println(integer);
            }
        });

二、 @functionalinterface函数式接口与lambda表达式

1、概念

//  consumer  @functionalinterface函数式接口

//  conceptually, a functional interface has exactly one abstract method.
//  从概念上看,一个函数式接口有且只有一个精确的抽象方法
//  从java8开始 接口中不仅仅存在抽象方法 还能存在有具体实现的方法(默认方法)

2、 函数式接口的区分

//  since {@linkplain java.lang.reflect.method#isdefault()
//  default methods} have an implementation, they are not abstract.  if
//  an interface declares an abstract method overriding one of the
//  public methods of {@code java.lang.object}, that also does
//  <em>not</em> count toward the interface's abstract method count
//  since any implementation of the interface will have an
//  implementation from {@code java.lang.object} or elsewhere.
//  因为java.lang.reflect.method#isdefault() default methods  有一个实现  所以不是抽象的
//  如果一个接口声明一个抽象方法,其实现了java.lang.object类中public方法:不计入抽象方法的个数

3、函数式接口的实例化方式

//  note that instances of functional interfaces can be created with
//  lambda expressions, method references, or constructor references.
//  函数式接口的实例化: lambda表达式 方法引用 构造方法引用

4、函数式接口中的默认方法

//   default void foreach(consumer<? super t> action) {
//       objects.requirenonnull(action);
//       for (t t : this) {
//           action.accept(t);
//       }
//   }

//   action  针对每个元素  执行的动作行为
//   default 修饰接口      已实现的默认方法

5、总结与思考

//  1、如果一个接口中有且只有一个抽象方法 则其为一个函数式接口
//  2、如果一个接口上声明了@functionalinterface注解 则编译器会按照函数式接口的定义来要求该接口

//  if a type is annotated with this annotation type, compilers are
//  required to generate an error message unless:
//  (1)the type is an interface type and not an annotation type, enum, or class.
//  (2)the annotated type satisfies the requirements of a functional interface.
//  however, the compiler will treat any interface meeting the
//  definition of a functional interface as a functional interface
//  regardless of whether or not a {@code functionalinterface}
//  annotation is present on the interface declaration.

//  3、如果接口上只有一个抽象方法,但我们没有对其加上@functionalinterface 编译器仍然将其看作函数式接口
//     加上注解后 一目了然  如果没有满足强制性要求 则会抛出错误信息

//  4、只有一个抽象方法的接口 有必要加上 @functionalinterface 如 runnable接口
//  5、所有的函数式接口 都可以使用lambda表达式 实现(表达易懂 简单)

三、函数式接口实例化 之 lambda表达式

system.out.println("--------------------lambda创建函数式接口实例---------------\n");
list.foreach(i -> {
    //  若能推断出i的类型 不需要声明
    //  如不能推断出(integer i)->{}
    system.out.println(i);
});

四、在排序过程中 lambda表达式的 演变

system.out.println("--------------------------lambda排序-----------------------\n");

//  collections.sort(list, new comparator<integer>() {
//      @override
//      public int compare(integer o1, integer o2) {
//         return o2.compareto(o1);
//     }
//  });

//  collections.sort(list,(string o1, string o2)->{return  o2.compareto(o1);});
//  collections.sort(list, (o1, o2) -> { return o2.compareto(o1); });
//  statement { return o2.compareto(o1); }
//  expression  o2.compareto(o1)
//  collections.sort(list,(string::compareto));
//  collections.sort(list,collections.reverseorder());

collections.sort(list, (o1, o2) -> o2.compareto(o1));
system.out.println(list);

五、函数式接口实例化 之 方法引用

system.out.println("--------------------方法引用创建函数式接口实例--------------\n");
list.foreach(system.out::println);
   }
}

六、深入理解lambda表达式

//  lambda表达式:

//  1、从函数式编程角度来看:
//  lambda表达式为java添加了函数式编程的新特性 函数升格成为一等公民
//  在函数作为一等公民的语言 如python中 lambda表达式为函数类型
//  但在java中 lambda表达式是对象类型 依赖于函数式接口functional interface

//   2、lambda表达式书写
//   lambda表达式形式 () -> {} 必需根据上下文确定其匿名函数类型  函数方法 -> 函数实现
//   () 省略  参数只有一个且类型可根据上下文推导
//   {} 省略  方法体主体只有一条语句,返回值类型与主体表达式(匿名函数)一致


//  3、进一步理解lambda表达式
//  lambda表达式传递行为action 不仅仅是值的传递 (类比node.js的事件驱动 与 回调函数callback)
//  lambda表达式替换前: 事先定义对象及所持有的方法 根据 “对象.方法” 进行方法的调用 预先定义好的action
//  lambda表达式替换后: {} 方法调用 r apply(t t); 事先不知道action  仅在调用时才知道 action
//  提升抽象层次 api重用性 使用灵活