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

函数式接口介绍

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

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

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

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

Java内置函数式接口

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

四大核心函数式接口

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

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

接口名抽象方法描述
BiConsumer<T,U>void accept(T t, U u)接收两个对象用于完成功能
DoubleConsumervoid accept(double value)接收一个double值
IntConsumervoid accept(int value)接收一个int值
LongConsumervoid accept(long value)接收一个long值
ObjDoubleConsumervoid accept(T t, double value)接收一个对象和一个double值
ObjIntConsumervoid accept(T t, int value)接收一个对象和一个int值
ObjLongConsumervoid accept(T t, long value)接收一个对象和一个long值

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

接口名抽象方法描述
BooleanSupplierboolean getAsBoolean()返回一个boolean值
DoubleSupplierdouble getAsDouble()返回一个double值
IntSupplierint getAsInt()返回一个int值
LongSupplierlong getAsLong()返回一个long值

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

接口名抽象方法描述
UnaryOperatorT apply(T t)接收一个T类型对象,返回一个T类型对象结果
DoubleFunctionR apply(double value)接收一个double值,返回一个R类型对象
IntFunctionR apply(int value)接收一个int值,返回一个R类型对象
LongFunctionR apply(long value)接收一个long值,返回一个R类型对象
ToDoubleFunctiondouble applyAsDouble(T value)接收一个T类型对象,返回一个double
ToIntFunctionint applyAsInt(T value)接收一个T类型对象,返回一个int
ToLongFunctionlong applyAsLong(T value)接收一个T类型对象,返回一个long
DoubleToIntFunctionint applyAsInt(double value)接收一个double值,返回一个int结果
DoubleToLongFunctionlong applyAsLong(double value)接收一个double值,返回一个long结果
IntToDoubleFunctiondouble applyAsDouble(int value)接收一个int值,返回一个double结果
IntToLongFunctionlong applyAsLong(int value)接收一个int值,返回一个long结果
LongToDoubleFunctiondouble applyAsDouble(long value)接收一个long值,返回一个double结果
LongToIntFunctionint applyAsInt(long value)接收一个long值,返回一个int结果
DoubleUnaryOperatordouble applyAsDouble(double operand)接收一个double值,返回一个double
IntUnaryOperatorint applyAsInt(int operand)接收一个int值,返回一个int结果
LongUnaryOperatorlong applyAsLong(long operand)接收一个long值,返回一个long结果
BiFunction<T,U,R>R apply(T t, U u)接收一个T类型和一个U类型对象,返回一个R类型对象结果
BinaryOperatorT apply(T t, T u)接收两个T类型对象,返回一个T类型对象结果
ToDoubleBiFunction<T,U>double applyAsDouble(T t, U u)接收一个T类型和一个U类型对象,返回一个double
ToIntBiFunction<T,U>int applyAsInt(T t, U u)接收一个T类型和一个U类型对象,返回一个int
ToLongBiFunction<T,U>long applyAsLong(T t, U u)接收一个T类型和一个U类型对象,返回一个long
DoubleBinaryOperatordouble applyAsDouble(double left, double right)接收两个double值,返回一个double结果
IntBinaryOperatorint applyAsInt(int left, int right)接收两个int值,返回一个int结果
LongBinaryOperatorlong applyAsLong(long left, long right)接收两个long值,返回一个long结果

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

接口名抽象方法描述
BiPredicate<T,U>boolean test(T t, U u)接收两个对象
DoublePredicateboolean test(double value)接收一个double值
IntPredicateboolean test(int value)接收一个int值
LongPredicateboolean 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("你喜欢的歌我也会去听 你喜欢的事物我也会想去了解");
}

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

在这里插入图片描述

@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));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值