你所不知道的Lambda表达式和常用的函数式接口,抓紧学起来

一. 什么Lambda表达式

Lambda表达式是JDK1.8中新增的一种方式,用于替代匿名内部类,该表达式可以让开发人员更加关注于具体需要传递的方法,而不是因为需要传递一个方法而创建一个对象。

二. Lambda表达式

1.基本语法

Lambda省去⾯向对象的条条框框,格式由3个部分组成:

参数部分

箭头

代码块

比如:(参数类型 参数名称) -> { 代码语句 }

2.格式说明

⼩括号内的语法与传统⽅法参数列表⼀致:⽆参数则留空;多个参数则⽤逗号分隔;

-> 是新引⼊的语法格式,代表指向动作;

⼤括号内的语法与传统⽅法体要求基本⼀致。

3.Lambda的省略格式

所谓的Lambda表达式的省略原则是:可推导即可省略。

Lambda强调的是“做什么”⽽不是“怎么做”,所以凡是可以根据上下⽂推导得知的信息,都可以省略。

3.1 省略规则

在Lambda标准格式的基础上,使⽤省略写法的规则为:

  • ⼩括号内参数的类型可以省略;

  • 如果⼩括号内有且仅有⼀个参,则⼩括号可以省略;

  • 如果⼤括号内有且仅有⼀个语句,则⽆论是否有返回值,都可以省略⼤括号、return关键字及语句、分号。

4.Lambda的使用前提

Lambda的语法⾮常简洁,完全没有⾯向对象复杂的束缚,但是使⽤时有⼏个问题需要特别注意:

  • 使⽤Lambda必须具有接⼝,且要求接口中有且仅有⼀个抽象方法。⽆论是JDK内置的Runnable 、 Comparator 接⼝还是⾃定义的接⼝,只有当接⼝中的抽象⽅法存在且唯⼀时,才可以使⽤Lambda。

  • 使⽤Lambda必须具有上下推断。也就是⽅法的参数或局部变量类型必须为Lambda对应的接⼝类型,才能使⽤Lambda作为该接⼝的实例。

5.常用函数式接口

JDK提供了⼤量常⽤的函数式接⼝以丰富Lambda的典型使⽤场景,它们主要在 java.util.function

包中被提供. 常用的函数式接口包括以下四个。

5.1 Supplier接口

java.util.function.Supplier 接⼝仅包含⼀个⽆参的⽅法:T get() 。⽤来获取⼀个泛型参数,可以指定类型的对象数据。由于这是⼀个函数式接⼝,这也就意味着对应的Lambda表达式需要“对外提供”⼀个符合泛型类型的对象数据。

5.1.1 基本使用方式如下

public class SupplierDemo {

//    为了获取一个int类型的数据
    private static int getNum(Supplier supplier) {
//        get方法 -- 返回一个指定数据类型 T 的数据
        return supplier.get();
    }

    public static void main(String[] args) {
//        int num = getNum(new Supplier() {
//            @Override
//            public Integer get() {
//                return 50;
//            }
//        });

        System.out.println(getNum(() -> 50));

//        1. 获取30  60 两个数字中的最大值
//        getNum(new Supplier() {
//            @Override
//            public Integer get() {
//                return Math.max(30,  60);
//            }
//        });
        getNum(()->Math.max(30, 60));

//        有一个数组
        int[] nums = {1,5,4,8,4,51,2,1,6,8};
//        通过getNum方法获取数组的最大值
//        getNum(new Supplier() {
//            @Override
//            public Integer get() {
//                Arrays.sort(nums);
//                return nums[nums.length - 1];
//            }
//        });

        int num = getNum(() -> {
            Arrays.sort(nums);
            return nums[nums.length - 1];
        });
        System.out.println(num);
    }
}

5.2 Consumer接口

java.util.function.Consumer 接⼝则正好与Supplier接⼝相反,它不是⽣产⼀个数据,⽽是消费⼀个数据,其数据类型由泛型决定。

  • Consumer接口中包含抽象⽅法 void accept(T t) ,意思是说消费⼀个执⾏泛型的数据

  • Consumer 接⼝中包含默认⽅法:andThen

如果⼀个⽅法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,⾸先做⼀个操作, 然后再做另⼀个操作,实现组合。⽽这个⽅法就是 Consumer 接⼝中的default⽅法 andThen。

5.2.1 下⾯是JDK的源代码:

default Consumer andThen(Consumersuper T> after) {
 Objects.requireNonNull(after);
 return (T t) -> { accept(t); after.accept(t); };
 }
基本使用方式如下:
public class ConsumerDemo {

//    使用一个指定的String类型的数据
    private static void useString(Consumer consumer, String string){
        consumer.accept(string);
    }

    private static void useString(Consumer consumer, Supplier supplier) {
        consumer.accept(supplier.get());
    }


//    返回的Consumer对象的目的 -- 使用accept方法接收参数,传递给first和second使用
    private static Consumer andThen(Consumer first, Consumer second){
        return new Consumer() {
            @Override
            public void accept(String s) {
                first.accept(s);
                second.accept(s);
            }
        };
    }
    private static void andThenTest(Consumer first, Consumer second, String string){
//        Consumer then = first.andThen(second);
//        then.accept(string);
//        前后两个接口对象之间,没有数据上的联系
//        两个接口 分别处理的都是原本的数据
        first.andThen(second).accept(string);
        System.out.println("---------");
        Consumer consumer = andThen(first, second);
        consumer.accept(string);
    }

    public static void main(String[] args) {
//        useString(new Consumer() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s.length());
//            }
//        }, "lambda");

//        useString((String s)->{
//            System.out.println(s.length());
//        }, "lambda");
        useString(s->System.out.println(s.length()), "lambda");
//        useString(s-> System.out.println(s), "lambda");
//        useString(System.out::println, "lambda");

        useString(s-> {
            System.out.println(s.concat(Integer.valueOf(s.length()).toString()));
            System.out.println(s + s.length());
        }, "lambda");

        useString(s->{
            System.out.println(s.length());
        },()->{
            return "123456oiuytr";
        });

        andThenTest(s -> System.out.println(s.toUpperCase()),
                s->System.out.println(s.substring(0, 3)), "lambda Exp");
    }
}

5.3 Predicate接口

有时候我们需要对某种类型的数据进⾏判断,从⽽得到⼀个boolean值结果。这时可以使

  • ⽤java.util.function.Predicate接⼝。

  • Predicate 接⼝中包含⼀个抽象⽅法:boolean test(T t)

  • 该接口也存在三个默认的方法,分别是and 、 or 和negate, 分别表示与 、或 、非三种逻辑处理。

5.3.1 接口代码示例

public class PredicateDemo {

    private static boolean testMethod(Predicate predicate, String s){
//        test方法返回一个boolean类型的数据
        return predicate.test(s);
    }

    private static boolean andMethod(Predicate first, Predicate second, String s){
        return first.and(second).test(s);
    }

    private static boolean orMethod(Predicate first, Predicate second, String s) {
        return first.or(second).test(s);
    }

    private static boolean negateMethod(Predicate predicate, String s) {
        return predicate.negate().test(s);
    }

    public static void main(String[] args) {
//        1. 判断一个字符串是否是由txt结尾的
//        boolean result = testMethod(new Predicate() {
//            @Override
//            public boolean test(String s) {
//                return s.endsWith("txt");
//            }
//        }, "newFile");
//        boolean result = testMethod((String s)->{
//                return s.endsWith("txt");
//        }, "newFile");
        boolean result = testMethod(s->s.endsWith("txt"), "newFile");
        System.out.println(result);

        boolean r1 = andMethod(s -> s.length() > 6,
                s -> s.startsWith("a"), "asijhgvbnm");

        boolean r2 = orMethod(s -> s.length() > 6,
                s -> s.equals("abcd"), "asdfghjkl");

        boolean r3 = negateMethod(s -> s.endsWith("a"), "asdfghjkl");

        System.out.println(r1 + " - " + r2 + " - " + r3);
    }
}

5.4 Function接口

java.util.function.Function接⼝⽤来根据⼀个类型的数据得到另⼀个类型的数据,前者称为前置条件,后者称为后置条件。

  • Function 接⼝中最主要的抽象⽅法是:R apply(T t) ,根据类型T的参数获取类型R的结果。

  • Function接⼝中有⼀个默认的andThen⽅法,⽤来进⾏组合操作。

5.4.1 基本使用方式如下

public class FunctionDemo {

    private static void applyMethod(Function function, String s){
        Integer apply = function.apply(s);
        System.out.println("从字符串" + s + "中获取的integer类型数据是:" + apply);
    }

    private static Function andThen(Function first, Function second){
//        T = String; R = Integer; V=Boolean
//        String --> Boolean
        return new Function() {
            @Override
            public Boolean apply(String s) {
//                String --> Integer
                Integer apply = first.apply(s);
//                Integer --> Boolean
                Boolean apply1 = second.apply(apply);
                return apply1;
            }
        };
    }
    private static void andThenMethod(Function first, Function second, String s){
        Function then = first.andThen(second);
//        因为andThen方法在实现的时候  前面一个的结果给后面一个处理
//        前者T R --> 后者 R V   ==> T  --> V
        Boolean apply = then.apply(s);
        System.out.println(apply);

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

        Function function = andThen(first, second);
        Boolean b = function.apply(s);
        System.out.println(b);
    }

    public static void main(String[] args) {
//        applyMethod(new Function() {
//            @Override
//            public Integer apply(String s) {
//                return s.indexOf("a");
//            }
//        }, "fashjkl");

//        applyMethod((String s)->{
//            return s.indexOf("a");
//        }, "fashjkl");

        applyMethod(s->s.indexOf("a"), "fashjkl");

        andThenMethod(s-> s.length(),
                i -> i > 20, "sadfghjkl;");

//        andThenMethod(String::length,
//                i -> i > 20, "sadfghjkl;");
    }
}

你可能感兴趣的:(java,前端,c#)