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

JAVA8核心语法梳理(1)Lambda表达式、函数式接口、方法引用

程序员文章站 2022-04-03 19:33:53
...

1 文章概述

JAVA13已经面世一段时间了,但是追根溯源一些新特性例如Lambda表达式、函数式接口、StreamAPI首次还在是出现在JAVA8。这些新特性有些开发者使用并不习惯,尤其链式编程感觉没有代码断句,可读性不强。但是JAVA8之所以逐渐流行确实是因为确实有许多优点:

  • 代码优雅
  • 易于并行
  • StreamAPI
  • Optional减少空指针

现在项目代码中越来越多出现JAVA8语法,为了读懂代码也需要我们熟悉JAVA8语法,本文介绍JAVA8如下重要特性,streamAPI我们下一篇文章再详细介绍。

  • Lambda表达式
  • 函数式接口
  • 方法引用

2 Lambda表达式

2.1 基本说明

Lambda表达式本质上是一个匿名函数,我们可以将一个Lambda表达式像参数一样进行传递。

public static void test01() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("公众号JAVA前线");
        }
    }).start();

    /** Lambda表达式 **/
    new Thread(() -> System.out.println("公众号JAVA前线")).start();
}

我们看到Lambda表达式6行代码缩短为1行,代码简洁而优雅,但是仅仅看代码并不好理解,下面我们介绍Lambda语法。

2.2 语法详解

Lambda表达式引入了->箭头操作符,箭头操作符左边指定表达式参数,右表是表达式执行体,下面我们根据参数个数的不同说明Lambda表达式语法。

(1) 无参数

public static void test02_NoParam() {
    Runnable task = () -> System.out.println("公众号JAVA前线");
    new Thread(task).start();
}

(2) 一个参数

单个参数可以不写小括号。假设一个方法参数类是字符串,在写Lambda表达式时并不要显示申明String类型,编译器可以根据上下文推断出类型,这就是类型推断。

import java.util.function.Consumer;

public static void test03_OneParam() {
    Consumer<String> c1 = (str) -> System.out.println(str);
    c1.accept("公众号JAVA前线");
    Consumer<String> c2 = str -> System.out.println(str);
    c2.accept("公众号JAVA前线");
}

上述例子使用了函数式接口Consumer我们后面再讲。

(3) 多个参数

如果Lambda体只有一行代码则花括号和return可以省略

public class Student {
    private int age;
    private String name;

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

public static void test04_MultiParam() {
    List<Student> list = new ArrayList<Student>();
    Collections.sort(list, new Comparator<Student>() {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    Collections.sort(list, (o1, o2) -> {
        return o1.getAge().compareTo(o2.getAge());
    });
    Collections.sort(list, (o1, o2) -> o1.getAge().compareTo(o2.getAge()));
}

3 函数式接口

函数式接口特点只包含了一个方法。JAVA8有四大内置函数式接口,其它内置函数式接口,还可以自定义函数式接口。

3.1 四大内置函数式接口

接口名 输入类型 输出类型 核心方法 说明
Consumer[T] T void accept(T) 消费型
Supplier[T] void T T get() 供给型
Function[T,R] T R R apply(T) 函数型
Predicate[T] T boolean boolean test(T) 判断型

(1) Consumer

Consumer作为消费型接口输入类型为T,没有输出类型

import java.util.function.Consumer;

public static void testConsumer() {
    Consumer<String> consumer = (str) -> {
        String newStr = "公众号" + str;
        System.out.println(newStr);
    };
    consumer.accept("JAVA前线");
}

(2) Supplier

Supplier作为供给型接口没有输入类型,输出类型为T

import java.util.function.Supplier;

public static void testSupplier() {
    Supplier<String> supplier = () -> {
        return "公众号JAVA前线";
    };
    String result = supplier.get();
    System.out.println(result);
}

(3) Function

Function作为函数型接口输入类型为T,输出类型为R

import java.util.function.Function;

public static void testFunction() {
    Function<String, Integer> function = (str) -> {
        if("公众号JAVA前线".equals(str)) {
            return 1;
        }
        return 0;
    };
    Integer result = function.apply("公众号JAVA前线");
    System.out.println(result);
}

(4) Predicate

Predicate作为判断型接口输入类型为T,输出类型为Boolean

import java.util.function.Predicate;

public static void testPredicate() {
    Predicate<String> predicate = (str) -> {
        if ("公众号JAVA前线".equals(str)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    };
    boolean result = predicate.test("公众号JAVA前线");
    System.out.println(result);
}

3.2 自定义函数接口

FunctionalInterface标识一个自定义函数式接口,我们可以根据需求定义功能强大的函数接口

/**
 * 自定义函数接口
 *
 * @author 公众号JAVA前线
 *
 * @param <T> 输入类型1
 * @param <R> 输入类型2
 * @param <U> 输出类型
 */
@FunctionalInterface
public interface MyInterfaceFunction<T, R, U> {
    public U bizMethod(T t, R r);
}

/**
 * 测试实例
 */
public class Java8_Function {
    public static void testMyFunction() {
        MyInterfaceFunction<String, String, Integer> myFuntion = (str1, str2) -> {
            if ("公众号".equals(str1) && "JAVA前线".equals(str2)) {
                return 1;
            }
            return 0;
        };
        Integer result = myFuntion.bizMethod("公众号", "JAVA前线");
        System.out.println(result);
    }
}

3.3 其它内置函数式接口

在四大内置函数式接口基础上,JAVA8提供了其它内置函数式接口,我们尝试列出一些并选择编写几个代码实例。

接口名 输入类型 输出类型 核心方法
BiConsumer[T,U] T、U void accept(T,U)
BiFunction[T,U,R] T、U R R apply(T,U)
UnaryOperator[T] T T T apply(T)
BinaryOperator[T] T、T T T apply(T,T)
ToIntFunction[T] T int int apply(T)
(1) BiFunction

BiFunction是Function函数增强版,允许两种输入类型

import java.util.function.BiFunction;

public static void testBiFunction() {
    BiFunction<String, String, Integer> biFunction = (str1, str2) -> {
        if ("公众号".equals(str1) && "JAVA前线".equals(str2)) {
            return 1;
        }
        return 0;
    };
    Integer result = biFunction.apply("公众号", "JAVA前线");
    System.out.println(result);
}
(2) BiConsumer

BiConsumer是Consumer函数增强版本,允许两种输入类型

import java.util.function.BiConsumer;

public static void testBiConsumer() {
    BiConsumer<String, String> biConsumer = (str1, str2) -> {
        System.out.println(str1 + str2);
    };
    biConsumer.accept("公众号", "JAVA前线");
}
(3) BinaryOperator

对类型为T的数据进行二元运算,并返回类型为T的结果

import java.util.function.BinaryOperator;

public static void testBinaryOperator() {
    BinaryOperator<String> biOperator = (str1, str2) -> {
        return str1 + str2;
    };
    String result = biOperator.apply("公众号", "JAVA前线");
    System.out.println(result);
}

4 方法引用

方法引用语法操作符是两个冒号,初看会让人比较费解。本章节我们来分析这个语法。当我们在编写Lambda方法体时,如果方法体的方法已经有现成实现,那么我们可以直接引用这个方法,这就是方法引用,需要注意的是参数列表必须一致。方法引用语法有四类:

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法
  • 类::new

4.1 对象::实例方法

public class Student {
    private String name;

    public String getName() {
        return name;
    }

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

public static void test01() {
    Consumer<String> c1 = (x) -> System.out.println(x);
    c1.accept("公众号JAVA前线");

    Consumer<String> c2 = System.out::println;
    c2.accept("公众号JAVA前线");

    Student student = new Student("公众号JAVA前线");
    Supplier<String> s1 = () -> student.getName();
    System.out.println(s1.get());

    Supplier<String> s2 = student::getName;
    System.out.println(s2.get());
}

4.2 类::实例方法

public class Student {
    private int age;
    private String name;

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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


public static void test02() {
    BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);
    System.out.println(bp1.test("公众号", "JAVA前线"));
    // 类::实例方法
    BiPredicate<String, String> bp2 = String::equals;
    System.out.println(bp2.test("公众号", "JAVA前线"));

    List<Student> list = new ArrayList<Student>();
    Collections.sort(list, new Comparator<Student>() {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    Collections.sort(list, (o1, o2) -> o1.getAge().compareTo(o2.getAge()));
    // 类::实例方法
    Collections.sort(list, Comparator.comparing(Student::getAge));
}

4.3 类::静态方法

public class Student {

    private int age;
    private String name;

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public static int compareAge(Student s1, Student s2) {
        return s1.getAge().compareTo(s2.getAge());
    }
}

public static void test03() {
    List<Student> list = new ArrayList<Student>();
    Collections.sort(list, new Comparator<Student>() {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    Collections.sort(list, (o1, o2) -> o1.getAge().compareTo(o2.getAge()));
    Collections.sort(list, Comparator.comparing(Student::getAge));
    // 类::静态方法
    Collections.sort(list, Student::compareAge);
}

4.4 类::new

public class Student {
    private String name;

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

public static void test04() {
    Function<String, Student> f1 = (str) -> new Student(str);
    System.out.println(f1.apply("公众号JAVA前线"));

    Function<String, Student> f2 = Student::new;
    System.out.println(f2.apply("公众号JAVA前线"));

    Function<Integer, Integer[]> f3 = (num) -> new Integer[num];
    System.out.println(f3.apply(15));

    Function<Integer, Integer[]> f4 = Integer[]::new;
    System.out.println(f4.apply(15));

    Supplier<List<Student>> s1 = () -> new ArrayList<Student>();
    System.out.println(s1.get());

    Supplier<List<Student>> s2 = ArrayList<Student>::new;
    System.out.println(s2.get());
}

5 文章总结

本文我们总结了Lambda表达式,函数式接口,方法引用语法,这些语法相较于传统语法改变不小,一开始并不容易理解,还需要反复实践。下一篇文章我们介绍JAVA8强大的StreamAPI语法请继续关注。

扫描二维码关注公众号【JAVA前线】获取更多互联网和技术干货,感谢各位支持

JAVA8核心语法梳理(1)Lambda表达式、函数式接口、方法引用

相关标签: 【JAVA】综合