JDK1.8新特性——lambda表达式和函数式接口

一、lambda表达式

1、概念

  • Lambda表达式时一种特殊的匿名内部类,语法更加简洁。
  • Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递

 这里的匿名内部类的理解,我们可以在下述情况中来帮助大家了解。

        我们都知道,接口是不能直接进行new的,即接口没有实例对象。那么我们之前想要new对象是不是还需要写该接口的一个实现类,然后再去new这个接口实现类的实例对象?

        在某些情况下,我们想要的也许只是接口中的一个抽象方法,其他的内容对我们来说都不重要,那么我们可以直接用接口的匿名内部类的方法来“new 这个接口”。

 对于这个Runnable接口,我们可以直接new他的匿名内部类。

package demo04;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/20 9:28
 **/
public class Test {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                //方法体
            }
        };
    }
}

对于 “=” 号后面的这一部分,都是他的匿名内部类。Lambda表达式就是一种特殊的匿名内部类。他的语法更加简洁。

注意,想要将匿名内部类改写为Lambda表达式的前提是,该接口必须为函数式接口(接口中只能有一个抽象方法的接口称为函数式接口)

 2、语法

<函数式接口> <变量名> = (参数1,参数2) ->{方法体};

注意:

  • (参数1,参数2): 抽象方法的参数
  • ->: 分隔符
  • { }:表示抽象方法的实现

我们还是用Runnable接口来举例子。Runnable接口就是一个函数式接口

 左边的代码就是Lambda表达式。他完全等价于右边匿名内部类的代码。

再强调一遍,想要使用Lambda表达式,该接口必须是函数式接口!

3、详细介绍Lambda表达式

  • Lambda表达式引入了新的操作符:->(箭头操作符),该操作符将表达式分成了两部分:
  1. 左侧:(参数1,参数2,...)表示参数列表(接口中抽象方法需要的参数列表)
  2. 右侧:"{}"的内部是方法体
  • 注意事项:
  1. 参数列表的数据类型会自动推断。我们在左侧括号内写参数列表时,不需要写参数的参数类型,直接写参数名即可。
  2. 如果参数列表为空,我们只需要写一个()即可(例如上面的Runnable接口中的run方法就的参数列表就为空)
  3. 如果参数列表只有一个,那么()可以省略,只需要写参数的名称即可
  4. 如果执行的语句只有一句,且无返回值,那么“{ }”可以省略不写;如果执行语句有返回值且只有一句,那么在省略“{ }”的同时,也要省略掉“return”关键字
  5. Lambda不会生成一个单独的内部类文件

二、函数式接口

1、概念

  • 如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用lambda表达式,Lambda表达式会被匹配到这个抽象方法上
  • @FunctionalInterface 注解会检测接口是否符合函数式接口

 2、内置函数式接口

        举个例子,我们想要用Lambda表达式来实现数组求和,就需要有一个函数式接口,那么我们就必须先定义一个函数式接口

@FunctionalInterface
interface Operater{
    //求数组的和
    public abstract void getSum(int[] arr);
}

然后再实现我们的求和功能

public class Test {

    public static void main(String[] args) {
        Operater o=arr -> {
             int sum=0;
             for(int n:arr){
                 sum+=n;
             }
            System.out.println("数组的和为:"+sum);
        };

        fun(o);
    }

    public static void fun(Operater operater){
         int[] arr={2,3,4,5,6,7,11};
         operater.getSum(arr);
    }

}

        我们知道使用Lambda表达式的前提是需要有函数式接口。而Lambda使用时不关心接口名,抽象方法名,只关心抽象方法的参数列表和返回值类型。因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口。这些接口都在java.util.function包下保存

这四种函数式接口我们都举一个例子来方便大家理解:

还是用我们的数组求和的代码。我们用Consumer,Supplier,Function这三种函数式接口对其进行改写,最后Predicate我们单独举个例子。

   自定义函数式接口实现数组求和的代码:

package FunctionalInterfaceTest;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/19 19:13
 * 求数组的和 ---- 传统形式
 **/
public class TraditionalMethod {
    public static void main(String[] args) {
        Num num = (arr)->{
            int sum = 0;
            for (Integer integer : arr) {
                sum+=integer;
            }
            System.out.println(sum);
        };
        fun(num);
    }

    public static void fun(Num num){
        Integer[] arr = {1,2,3,4,5,6,7,8,9};
        num.getNum(arr);
    }

}

interface Num{
    public void getNum(Integer[] arr);
}

2.1 Consumer<T> 消费型函数式接口 有参无返回值

T:参数类型的泛型

该函数式接口的抽象方法为  accept( 参数名 );

package FunctionalInterfaceTest;

import java.util.function.Consumer;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/19 19:19
 * 求数组的和
 * 有参无返   消费型
 **/
public class ConsumerMethod {
    public static void main(String[] args) {
        Consumer<Integer[]> consumer = (arr)->{
            int sum = 0;
            for (Integer integer : arr) {
                sum+=integer;
            }
            System.out.println(sum);
        };
        Integer[] integers = {1,2,3,4,5,6,7,8,9};
        fun(consumer,integers);
    }


    public static void fun(Consumer<Integer[]> consumer,Integer[] arr){
        consumer.accept(arr);
    }
}

2.2 Supplier<T> 供给型函数式接口 无参有返回值

T:返回结果的泛型

该函数式接口的抽象方法为    T   get( );

package FunctionalInterfaceTest;

import java.util.function.Supplier;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/19 19:22
 * 求数组的和
 * 无参有返回值   供给型
 **/
public class SupplierMethod {
    public static void main(String[] args) {
        Supplier<Integer> supplier = ()->{
            Integer[] integers = {1,2,3,4,5,6,7,8,9};
            Integer sum = 0;
            for (Integer integer : integers) {
                sum+=integer;
            }
            return sum;
        };
        fun(supplier);
    }

    public static void fun(Supplier<Integer> supplier){
        Integer integer = supplier.get();
        System.out.println(integer);
    }
}

2.3 Function<T,R> 函数型函数式接口  有参有返回值

T:参数类型的泛型

R:函数返回结果的泛型

其抽象方法为: R  apply( 参数名 )

package FunctionalInterfaceTest;

import java.util.function.Function;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/19 19:28
 * 求数组的和/传入一个字符串,返回字符串的长度
 * 有参 有返回值   函数型
 **/
public class FunctionMethod {
    public static void main(String[] args) {

        //数组求和
        Function<Integer[],Integer> function = (arr)->{
            Integer sum = 0;
            for (Integer integer : arr) {
                sum+=integer;
            }
            return sum;
        };
        Integer[] arr = {1,2,3,4,5,6,7,8,9};
        fun(function,arr);


        //计算字符串的长度
        getLength(str->str.length(),"hello lambda");
    }

    //数组求和方法
    public static void fun(Function<Integer[],Integer> function,Integer[] arr){
        Integer apply = function.apply(arr);
        System.out.println(apply);
    }

    public static void getLength(Function<String,Integer> function,String str){
        Integer apply = function.apply(str);
        System.out.println("该字符串的长度为:"+apply);
    }
}

 2.4 Predicated<T>  断言型函数式接口 有参,返回布尔值

T:参数类型的泛型

抽象方法: boolean test(参数名)

 例子:判断传入字符串的长度是否大于10

package FunctionalInterfaceTest;

import java.util.function.Predicate;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/19 19:31
 * 判断字符串的长度是否大于10
 **/
public class PredicatedMethod {
    public static void main(String[] args) {
        NameIsBigThanThree(name->name.length()>10?true:false,"达拉崩吧版的本地不多秘鲁翁");
    }

    public static void NameIsBigThanThree(Predicate<String> predicate,String name){
        boolean test = predicate.test(name);
        System.out.println("该字符串长度大于10是"+test);
    }
}

三、方法引用

1、lambda表达式的冗余

如果我们在Lambda中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻辑?可以直接“引 用”过去就好了:---方法引用。

public class Test01 {

    public static void main(String[] args) {

        Consumer<Integer[]> c=Test01::sum;

        fun(c);
    }


    public static void fun(Consumer<Integer[]>  consumer){
          Integer[] arr={1,2,3,4,5};
          consumer.accept(arr);
    }

    public static void sum(Integer[] arr){
          int sum=0;
          for (int a:arr){
              sum+=a;
          }
        System.out.println("数组的和为:"+sum);
    }

}

请注意其中的双冒号 :: 写法,这被称为“方法引用”,是一种新的语法。

2、 什么是方法引用

 方法引用的分类:

 四种引用方法具体例子:

2.1 静态方法引用

类名::静态方法     代替-->      (参数)->类名.静态方法(参数)

 对象类型数组或集合的排序:

package referencedByMethodsTest;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/19 19:42
 * 排序
 **/
public class StaticMethodReferencedTest {
    public static void main(String[] args) {

        //Person数组
        Person[] ps ={new Person("张三",18),new Person("李四",25),new Person("王五",20),new Person("张三",19)};
        Arrays.sort(ps,Person::compareTo);
        for (Person p : ps) {
            System.out.println(p+"```````数组````````");
        }

        //Person集合
        List<Person> list = new ArrayList<>();
        list.add(new Person("张三",51));
        list.add(new Person("李四",35));
        list.add(new Person("王五",27));
        list.add(new Person("赵六",60));
        list.sort(Person::compareTo);
        for (Person person : list) {
            System.out.println(person+"========集合======");
        }
    }
}

class Person{
    private String name;
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    //自定义排序方法
    public static int compareTo(Person o1,Person o2){
        return o2.age - o1.age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

2.2  实例方法引用

对象::实例方法      代替-->      (参数)->对象.实例方法(参数)

        实例方法引用,顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化,静态方法引用类无需实例化,直接用类名去调用。  

 例子和静态方法引用里面的例子相同,注意二者的区别

package referencedByMethodsTest;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/19 20:24
 **/
public class InstanceMethodReferencedTest {
    public static void main(String[] args) {
        //people数组排序
        People[] people = {new People("张三",15),new People("李四",27),new People("王五",19),new People("赵六",35)};
        People people1 = new People();
        //实例方法引用
        Arrays.sort(people,people1::compareTo);
        for (People people2 : people) {
            System.out.println(people2+"------数组排序-----");
        }

        //people集合排序
        List<People> list = new ArrayList<>();
        list.add(new People("张三",55));
        list.add(new People("李四",37));
        list.add(new People("王五",68));
        list.add(new People("赵六",25));
        list.sort(people1::compareTo);
        for (People people2 : list) {
            System.out.println(people2+"++++++集合排序++++++");
        }
    }

}

class People {
    private String name;
    private Integer age;

    public People() {
    }

    public People(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    //自定义排序方法
    public int compareTo(People o1, People o2){
        return o2.age - o1.age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

2.3 对象方法引用

类名::实例方法          代替-->          (参数1,参数2)->参数1.实例方法(参数2)    

package test.methodReference;

import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/20 18:59
 * 对象引用方法     类::实例方法    替换   (参数1,参数2)->参数1.实例方法(参数2)
 **/
public class ObjectReferenceMethod {
    public static void main(String[] args) {
        //比较两个字符串的值是否相等
        //Lambda表达式方法
        BiFunction<String,String,Boolean> function = (t1,t2)->t1.equals(t2);
        Boolean apply = function.apply("hello", "hello");
        System.out.println(apply);
        //对象引用方法
        BiFunction<String,String,Boolean> function1 = String::equals;
        Boolean apply1 = function1.apply("hello", "hello");
        System.out.println(apply1);

        //计算字符串的长度
        //lambda表达式
        Function<String,Integer> function2 = (str)->str.length();
        Integer hello_world = function2.apply("hello world");
        System.out.println(hello_world);
        //对象引用方法
        Function<String,Integer> function3 = String::length;
        Integer hello_world1 = function3.apply("hello world");
        System.out.println(hello_world1);
    }
}

2.4 构造方法引用

类名::new                 代替-->          (参数)->new 类名(参数)          

package test.methodReference;

import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/20 19:09
 *  构造方法引用   类名::new   替换   (参数)->new  类名(参数)
 **/
public class ConstructorReferenceMethod {
    public static void main(String[] args) {
        //(1) new String
        //Lambda表达式
        Function<String,String> function = (str)->new String(str);
        String hello_world = function.apply("hello world");
        System.out.println(hello_world);
        //构造方法引用
        Function<String,String> function1 = String::new;
        String hello_world1 = function1.apply("hello world");
        System.out.println(hello_world1);


        //(2) new Person

        //lambda表达式
        BiFunction<String,Integer,Person> biFunction = (name,age)->new Person(name,age);
        Person p = biFunction.apply("张三", 18);
        System.out.println(p);
        //构造方法引用
        BiFunction<String,Integer,Person> biFunction1 = Person::new;
        System.out.println(biFunction1.apply("张三",18));
    }
}
class Person{
    private String name;
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值