【jdk8新特性】lambda表达式函数式接口

简介: 【jdk8新特性】lambda表达式函数式接口

【jdk8新特性】lambda表达式函数式接口

什么是函数式接口

函数式接口在Java中是指:有且仅有一个抽象方法的接口。

为什么需要函数式接口

因为写lambda表达式的前提是需要参数或者变量为函数式接口

自定义函数接口

例子:

public class Demo01UserFunctionalInterface {
    public static void main(String[] args) {
        test((int a, int b) -> {
            System.out.println(a + b);
        });
    }
    public static void test(Operation op) {
        op.getSum(1, 2);
    }
}
interface Operation {
    public abstract void getSum(int a, int b);
}

结果

3

这个例子中Operation就是函数式接口

常用的内置函数接口

Supplier

源代码

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

可以看出这个函数式接口的抽象方法是get,且不需要参数,所以这个Supplier接口的作用是 无需传参处理数据获得返回值,它意味着"供给" , 对应的Lambda表达式需要“对外提供”一个符合泛型类 型的对象数据。

例子

public class Demo02Supplier {
    // 使用Lambda表达式返回数组元素最大值
    public static void main(String[] args) {
        System.out.println("开始了");
        printMax(() -> {
            int[] arr = {11, 99, 88, 77, 22};
            Arrays.sort(arr); // 升序排序
            return arr[arr.length - 1];
        });
    }
    public static void printMax(Supplier<Integer> supplier) {
        System.out.println("aa");
        int max = supplier.get();
        System.out.println("max = " + max);
    }
}

结果

开始了
aa
max = 99

可以看出 printMax方法的参数类型是 Supplier函数式接口 所以我们可以使用lambda表达式,我们重写了 Supplier的get方法 内容是一个链表的升序排序 并返回最大值

Consumer

源代码

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

可以看出 Consumer函数式接口 只有一个抽象方法accept(T t) 以及一个 默认方法andThen(Consumer),accept方法需要一个参数并且没有返回值,它不是生产一个数据,而是消费一个数据,其数据类型由泛 型参数决定。

例子

public class Demo03Consumer {
    // 使用Lambda表达式将一个字符串转成大写的字符串
    public static void main(String[] args) {
        System.out.println("开始啦");
        printHello((String str) -> {
            System.out.println(str.toUpperCase());
        });
    }

    public static void printHello(Consumer<String> consumer) {
        System.out.println("aaa");
        consumer.accept("Hello World");
    }
}

可以看出 printHello方法的参数类型是 Consumer函数式接口 所以我们可以使用lambda表达式,我们重写了 Supplier的accept方法 内容是一个链表的升序排序 并返回最大值

默认方法:andThen

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

例子

public class Demo04ConsumerAndThen {
    // 使用Lambda表达式先将一个字符串转成小写的字符串,再转成大写
    public static void main(String[] args) {
        System.out.println("开始啦");
        printHello((String str) -> {
            System.out.println(str.toLowerCase());
        }, (String str) -> {
            System.out.println(str.toUpperCase());
        });
    }

    public static void printHello(Consumer<String> c1, Consumer<String> c2) {
        System.out.println("aa");
        String str = "Hello World";
        // c1.accept(str);
        // c2.accept(str);

        c2.andThen(c1).accept(str);

    }
}

结果

aa
HELLO WORLD
hello world

可以看出运行结果将会首先打印完全大写的HELLO,然后打印完全小写的hello。当然,通过链式写法可以实现更多步骤的组合。

Function

源代码

public interface Function<T, R> {

    R apply(T t);
    
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

可以看出 Function函数式接口 只有一个抽象方法R apply(T t),需要参数和返回值,用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件, 后者称为后置条件。有参数有返回值。

例子

public class Demo05Function {
    // 使用Lambda表达式将字符串转成数字
    public static void main(String[] args) {
        System.out.println("开始");
        getNumber((String str) -> {
            int i = Integer.parseInt(str);
            return i;
        });
    }

    public static void getNumber(Function<String, Integer> function) {
        System.out.println("aa");
        Integer num1 = function.apply("10");
        System.out.println("num1 = " + num1);
    }
}

结果

开始
aa
num1 = 10

可以看出 Function接口的apply方法 对字符串10 进行处理 返回整型10

Predicate接口

public interface Predicate<T> {

    boolean test(T t);


    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }


    default Predicate<T> negate() {
        return (t) -> !test(t);
    }


    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }


    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }


    @SuppressWarnings("unchecked")
    static <T> Predicate<T> not(Predicate<? super T> target) {
        Objects.requireNonNull(target);
        return (Predicate<T>)target.negate();
    }
}

可以看出 Predicate函数式接口 只有一个抽象方法 boolean test(T t);需要一个参数并返回boolean类型,有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果,这时可以使用Predicate接口。

例子

public class Demo07Predicate {
    // 使用Lambda判断一个人名如果超过3个字就认为是很长的名字
    public static void main(String[] args) {
        System.out.println("开始啦");
        isLongName((String name) -> {
            return name.length() > 3;
        });
    }

    public static void isLongName(Predicate<String> predicate) {
        System.out.println("aa");
        boolean isLong = predicate.test("迪丽热巴");
        System.out.println("是否是长名字: " + isLong);
    }
}

结果

开始啦
aa
是否是长名字: true

可以看出传入一个长度为4的字符串 test方法里进行判断是否 长度>3 返回true

默认方法:and,or,negate

解释

and:将两个 Predicate 条件使用“与”逻辑连接起来实 现“并且”的效果时,可以使用default方法 and 。

or:将两个 Predicate 条件使用“与”逻辑连接起来实 现“或”的效果时,可以使用default方法 or。

negate:Predicate 中的"取反,非"。

例子

// 使用Lambda表达式判断一个字符串中即包含W,也包含H
// 使用Lambda表达式判断一个字符串中包含W或者包含H
// 使用Lambda表达式判断一个字符串中不包含W
public static void main(String[] args) {
    test((String str) -> {
        // 判断是否包含W
        return str.contains("W");
    }, (String str) -> {
        // 判断是否包含H
        return str.contains("H");
    });
}

public static void test(Predicate<String> p1, Predicate<String> p2) {
    // String str = "Hello orld";
    // boolean b1 = p1.test(str);
    // boolean b2 = p2.test(str);
    // if (b1 && b2) {
    //     System.out.println("即包含W,也包含H");
    // }
    // 使用Lambda表达式判断一个字符串中即包含W,也包含H
    String str = "Hello World";
    boolean b = p1.and(p2).test(str);
    if (b) {
        System.out.println("即包含W,也包含H");
    }

    // 使用Lambda表达式判断一个字符串中包含W或者包含H
    boolean b1 = p1.or(p2).test(str);
    if (b1) {
        System.out.println("包含W或者包含H");
    }
    // 使用Lambda表达式判断一个字符串中不包含W
    boolean b2 = p1.negate().test("Hello W");
    // negate相当于取反 !boolean
    if (b2) {
        System.out.println("不包含W");
    }
}

结果

即包含W,也包含H
包含W或者包含H
目录
相关文章
|
1月前
|
安全 JavaScript 前端开发
JDK1.8的重要的新特性与功能
Java Development Kit (JDK) 1.8,也称为Java 8,是Java平台的一个重大更新,于2014年3月发布。它引入了多项新特性、新的API和性能提升
72 3
|
2月前
|
监控 安全 Java
探索Java的未来:JDK 18新特性全览
探索Java的未来:JDK 18新特性全览
70 0
|
2月前
|
缓存 安全 Java
JDK 14全景透视:每个Java开发者必知的新特性
JDK 14全景透视:每个Java开发者必知的新特性
51 0
|
1月前
|
Java
JDK8新特性--lambda表达式
面向对象思想强调:必须通过对象的形式来做事情
JDK8新特性--lambda表达式
|
2月前
|
前端开发 IDE Java
JDK 新特性学习笔记之模块系统
JDK 新特性学习笔记之模块系统
|
2月前
|
Java 应用服务中间件 开发工具
最简单JDK安装指南(小白也能一次性安装完成)
最简单JDK安装指南(小白也能一次性安装完成)
|
3月前
|
Java
安装JAVA_JDK快速入门
安装JAVA_JDK快速入门
|
7天前
|
Oracle Java 关系型数据库
Java 开发者必备:JDK 版本详解与选择策略(含安装与验证)
Oracle Java SE 支持路线图显示,JDK 8(LTS)支持至2030年,非LTS版本如9-11每6个月发布且支持有限。JDK 11(LTS)支持至2032年,而JDK 17及以上版本现在提供免费商用许可。LTS版本提供长达8年的支持,每2年发布一次。Oracle JDK与OpenJDK有多个社区和公司构建版本,如Adoptium、Amazon Corretto和Azul Zulu,它们在许可证、商业支持和更新方面有所不同。个人选择JDK时,可考虑稳定性、LTS、第三方兼容性和提供商支持。
18 0
|
14天前
|
Java Linux 开发工具
linux jdk的安装
linux jdk的安装
16 0
|
27天前
|
Java Linux
linux安装jdk环境
linux安装jdk环境
29 0