01-详细介绍函数式接口和Lambda表达式语法

函数式接口介绍

如果在一个接口中只声明了一个抽象方法,则此接口就被称为函数式接口(该接口可以包含其他非抽象方法)

  • 接口上使用@FunctionalInterface注解可以验证该接口是否为函数式接口,javadoc生成的文档时也会保留该注解, 若接口中有多个抽象方法编译器会报错

随着Python,Scala等语言的兴起和新技术的挑战,Java不得不做出调整以便支持更加广泛的技术要求,所以Java8不但可以支持OOP还可以支持OOF(面向函数编程)

  • 面向对象编程思想:完成一件事情需要找一个能解决这个事情的对象然后调用对象的方法
  • 函数式编程思想: 重视结果不重视过程,只要能获取到结果即可,无论谁去做又怎么做
  • 在函数式编程语言当中Lambda表达式的类型是函数,但在Java8中Lambda表达式是对象而不是函数,它们必须依附于函数式接口

Java内置函数式接口

java.util.function包下定义了Java8的丰富的函数式接口

四大核心函数式接口

函数式接口 称谓 参数类型 用途
Consumer 消费型接口 T 对类型为T的对象应用操作,包含方法 void accept(T t)
Supplier 供给型接口 返回类型为T的对象,包含方法T get()
Function 函数型接口 T 对类型为T的对象应用操作并返回结果R类型的对象,包含方法R apply(T t)
Predicate 判断型接口 T 确定类型为T的对象是否满足某约束并返回 boolean 值,包含方法boolean test(T t)

消费型接口: 抽象方法有形参但是返回值类型是void

接口名 抽象方法 描述
BiConsumer void accept(T t, U u) 接收两个对象用于完成功能
DoubleConsumer void accept(double value) 接收一个double值
IntConsumer void accept(int value) 接收一个int值
LongConsumer void accept(long value) 接收一个long值
ObjDoubleConsumer void accept(T t, double value) 接收一个对象和一个double值
ObjIntConsumer void accept(T t, int value) 接收一个对象和一个int值
ObjLongConsumer void accept(T t, long value) 接收一个对象和一个long值

供给型接口: 抽象方法无参但是有返回值

接口名 抽象方法 描述
BooleanSupplier boolean getAsBoolean() 返回一个boolean值
DoubleSupplier double getAsDouble() 返回一个double值
IntSupplier int getAsInt() 返回一个int值
LongSupplier long getAsLong() 返回一个long值

函数型接口: 抽象方法既有参数又有返回值

接口名 抽象方法 描述
UnaryOperator T apply(T t) 接收一个T类型对象,返回一个T类型对象结果
DoubleFunction R apply(double value) 接收一个double值,返回一个R类型对象
IntFunction R apply(int value) 接收一个int值,返回一个R类型对象
LongFunction R apply(long value) 接收一个long值,返回一个R类型对象
ToDoubleFunction double applyAsDouble(T value) 接收一个T类型对象,返回一个double
ToIntFunction int applyAsInt(T value) 接收一个T类型对象,返回一个int
ToLongFunction long applyAsLong(T value) 接收一个T类型对象,返回一个long
DoubleToIntFunction int applyAsInt(double value) 接收一个double值,返回一个int结果
DoubleToLongFunction long applyAsLong(double value) 接收一个double值,返回一个long结果
IntToDoubleFunction double applyAsDouble(int value) 接收一个int值,返回一个double结果
IntToLongFunction long applyAsLong(int value) 接收一个int值,返回一个long结果
LongToDoubleFunction double applyAsDouble(long value) 接收一个long值,返回一个double结果
LongToIntFunction int applyAsInt(long value) 接收一个long值,返回一个int结果
DoubleUnaryOperator double applyAsDouble(double operand) 接收一个double值,返回一个double
IntUnaryOperator int applyAsInt(int operand) 接收一个int值,返回一个int结果
LongUnaryOperator long applyAsLong(long operand) 接收一个long值,返回一个long结果
BiFunction R apply(T t, U u) 接收一个T类型和一个U类型对象,返回一个R类型对象结果
BinaryOperator T apply(T t, T u) 接收两个T类型对象,返回一个T类型对象结果
ToDoubleBiFunction double applyAsDouble(T t, U u) 接收一个T类型和一个U类型对象,返回一个double
ToIntBiFunction int applyAsInt(T t, U u) 接收一个T类型和一个U类型对象,返回一个int
ToLongBiFunction long applyAsLong(T t, U u) 接收一个T类型和一个U类型对象,返回一个long
DoubleBinaryOperator double applyAsDouble(double left, double right) 接收两个double值,返回一个double结果
IntBinaryOperator int applyAsInt(int left, int right) 接收两个int值,返回一个int结果
LongBinaryOperator long applyAsLong(long left, long right) 接收两个long值,返回一个long结果

判断型接口: 抽象方法特点有参但是返回值类型是boolean结果

接口名 抽象方法 描述
BiPredicate boolean test(T t, U u) 接收两个对象
DoublePredicate boolean test(double value) 接收一个double值
IntPredicate boolean test(int value) 接收一个int值
LongPredicate boolean test(long value) 接收一个long值

接口的使用

消费型接口使用举例

// 消费性接口
public interface Consumer<Double>{
    void accept (Double money);
}

public void happyTime(double money, Consumer<Double> consumer) {
    // 调用消费型接口的方法
    consumer.accept(money);
}
@Test
public void test04() {
    // 传统写法
    happyTime(1241, new Consumer<Double>() {
        @Override
        public void accept(Double money) {
            System.out.println("突然想回一趟成都了,机票花费" + money);
        }
    });
    System.out.println("------------------------");

    // Lambda表达式
    happyTime(648, money -> System.out.println("学习太累了,奖励自己一发十连,花费" + money));
}

断定型接口使用举例: 根据Predicate接口实现类的实现方法给定的规则,过滤集合中的字符串

public List<String> filterString(List<String> strings, Predicate<String> predicate) {
    ArrayList<String> res = new ArrayList<>();
    for (String string : strings) {
        if (predicate.test(string))
            res.add(string);
    }
    return res;
}

@Test
public void test05() {
    List<String> strings = Arrays.asList("东京", "西京", "南京", "北京", "天津", "中京");
    // 传统写法
    List<String> list = filterString(strings, new Predicate<String>() {
        @Override
        public boolean test(String s) {
            return s.contains("京");
        }
    });
    System.out.println(list);

    System.out.println("------------------------");

    // Lambda表达式
    List<String> res = filterString(strings, s -> s.contains("京"));
    System.out.println(res);
}

Lambda表达式语法的使用

匿名内部类

当需要启动一个线程去完成任务时,通常会通过java.lang.Runnable接口来定义任务内容并使用java.lang.Thread类来启动该线程

  • Thread类需要Runnable接口作为参数,其中的抽象run方法是用来指定线程任务内容的核心
  • 为了指定run的方法体需要创建Runnable接口的实现类,为了省去定义一个RunnableImpl实现类的麻烦需要使用匿名内部类
  • 编写的匿名内部类必须覆盖重写抽象run方法,所以方法名称、方法参数、方法返回值都需要再写一遍且不能写错, 而实际上只有方法体才是关键所在
public class UseFunctionalProgramming {
    public static void main(String[] args) {
        // new 接口(){实现类}
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("多线程任务执行!");
            }
        }).start(); // 启动线程
    }
}

Lambda表达式的6种形式

我们可以通过Lambda表达式创建函数式接口的实现类对象代替匿名实现类,Lambda表达式是用来简化函数式接口的变量或形参赋值的语法

  • 因为函数式接口只有一个抽象方法,所以我们才可以省略方法名称,方法参数,方法返回值,@Override函数声明等内容
new Thread(() -> {
	System.out.println("多线程任务执行!");
}).start(); 

Lambda表达式的语法格式如(o1,o2) -> Integer.compare(o1,o2)

  • ->:lambda操作符或箭头操作符
  • ->左边(函数式接口中抽象方法的形参列表):因为有类型推断机制形参的数据类型都可以省略,如果只有一个参数,参数的小括号可以省略
  • ->右边{函数式接口中抽象方法的方法体}: 当Lambda体只有一条语句时(return语句或其他语句),如果是return语句return与{}需要一起省略, 不能只省略{}return不能单独出现

语法格式一: 函数式接口的抽象方法无参无返回值

@Test
public void test01(){
    // 传统写法
    Runnable runnable01 = new Runnable() {
        @Override
        public void run() {
            System.out.println("你 的 城 市 好 像 不 欢 迎 我");
        }
    };
    runnable01.run();
    System.out.println("-------------------------");
    // Lambda表达式
    Runnable runnable02 = () -> {
        System.out.println("所 以 我 只 好 转 身 离 开 了");
    };
    runnable02.run();
}

语法格式二: 函数式接口的抽象方法有一个参数但是没有返回值

@Test
public void test03(){
    //1. 传统写法
    Consumer<String> consumer01 = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    };
    consumer01.accept("其实我存过你照片 也研究过你的星座");

    System.out.println("-------------------------");
    // Lambda表达式
    Consumer<String> consumer02 = (String s) -> {
        System.out.println(s);
    };
    consumer02.accept("你喜欢的歌我也会去听 你喜欢的事物我也会想去了解");
}

语法格式三: 函数式接口抽象方法中形参列表的数据类型可以省略,编译器可由类型推断机制得出,底层是由声明变量的泛型类型推断得出

01-详细介绍函数式接口和Lambda表达式语法_第1张图片

@Test
public void test() {
    //类型推断机制1
    ArrayList<String> list = new ArrayList<>();
    //类型推断机制2
    int[] arr = {1, 2, 3};

}
@Test
public void test04(){
    // 传统写法
    Consumer<String> consumer01 = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    };
    consumer01.accept("我远比表面上更喜欢你");

    System.out.println("-------------------------");
    // Lambda表达式
    Consumer<String> consumer02 = (s) -> {
        System.out.println(s);
    };
    consumer02.accept("但我没有说");
}

语法格式四: 函数式接口的抽象方法只有一个参数,参数的小括号可以省略

@Test
public void test04(){
    // 传统写法
    Consumer<String> consumer01 = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    };
    consumer01.accept("我远比表面上更喜欢你");

    System.out.println("-------------------------");
    // Lambda表达式
    Consumer<String> consumer02 = s -> {
        System.out.println(s);
    };
    consumer02.accept("但我没有说");
}

语法格式五: 函数式接口的抽象方法有两个或以上参数,方法有返回值,方法体有多条执行语句

@Test
public void test02() {
    // 传统的写法
    Comparator<Integer> comparator01 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        }
    };
    System.out.println(comparator01.compare(95, 27));
    System.out.println("-------------------------");

    // Lambda表达式
    Comparator<Integer> comparator02 = (o1, o2) -> {
        System.out.println(o1);
        System.out.println(o2);
        return o1.compareTo(o2);
    };
    System.out.println(comparator02.compare(12, 21));
}

语法格式六: 当Lambda体只有一条语句时(可能是return语句),如果是return语句return与{}需要一起省略, 注意不能只省略{}return不能单独出现

public void test02() {
    // 传统写法
    Comparator<Integer> comparator01 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1.compareTo(o2);
        }
    };
    System.out.println(comparator01.compare(95, 27));
    System.out.println("-------------------------");

    // Lambda表达式
    Comparator<Integer> comparator02 = (o1, o2) -> o1.compareTo(o2);
    System.out.println(comparator02.compare(12, 21));
}

你可能感兴趣的:(Java8,开发语言,Java8,函数式接口,Lambda表达式)