【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
目录
相关文章
|
6月前
|
开发框架 Java 关系型数据库
在Linux系统中安装JDK、Tomcat、MySQL以及部署J2EE后端接口
校验时,浏览器输入:http://[your_server_IP]:8080/myapp。如果你看到你的应用的欢迎页面,恭喜你,一切都已就绪。
510 17
|
6月前
|
Java 关系型数据库 MySQL
在Linux操作系统上设置JDK、Tomcat、MySQL以及J2EE后端接口的部署步骤
让我们总结一下,给你的Linux操作系统装备上最强的军队,需要先后装备好JDK的弓箭,布置好Tomcat的阵地,再把MySQL的物资原料准备好,最后部署好J2EE攻城车,那就准备好进军吧,你的Linux军团,无人可挡!
159 18
|
6月前
|
开发框架 关系型数据库 Java
Linux操作系统中JDK、Tomcat、MySQL的完整安装流程以及J2EE后端接口的部署
然后Tomcat会自动将其解压成一个名为ROOT的文件夹。重启Tomcat,让新“植物”适应新环境。访问http://localhost:8080/yourproject看到你的项目页面,说明“植物”种植成功。
214 10
|
8月前
|
Java 测试技术 调度
JDK21有没有什么稳定、简单又强势的特性?
这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。
JDK21有没有什么稳定、简单又强势的特性?
|
11月前
|
容器
jdk8新特性-详情查看文档
jdk8新特性-详情查看文档
183 7
安装JDK18没有JRE环境的解决办法
安装JDK18没有JRE环境的解决办法
1287 141
|
4月前
|
存储 Ubuntu 安全
在Ubuntu 16.04上安装openjdk-6/7/8-jdk的步骤
在整个安装过程中,你可能需要管理员权限,因此你可能要使用 `sudo` 来获取必要的权限。记得做完每一个步骤后,都要检查输出,以确保没有发生错误,并且每项操作都成功完成。如果在安装过程中遇到问题,查看 `/var/log/` 下的日志文件对于问题的解决可能是有帮助的。
319 21
|
4月前
|
IDE Ubuntu Java
在Ubuntu18.04安装兼容JDK 8的Eclipse集成开发环境的指南。
完成以上步骤后,您将在Ubuntu 18.04系统上成功安装并配置了Eclipse IDE,它将与JDK 8兼容,可以开始进行Java开发工作。如果遇到任何问题,请确保每一步骤都正确执行,并检查是否所有路径都与您的具体情况相匹配。
211 11
|
3月前
|
Ubuntu Java Android开发
在Ubuntu 18.04上安装与JDK 8兼容的Eclipse版本的步骤。
安装过程结束后,您就可以开始使用Eclipse来开发您的Java项目了,并且确保它与JDK 8兼容无误。这个过程涉及的是一个基本的安装流程,针对使用Java 8的用户,Eclipse的其他配置和插件安装根据个人开发环境和需求来定制。
303 0
|
6月前
|
Java 关系型数据库 MySQL
在Linux平台上进行JDK、Tomcat、MySQL的安装并部署后端项目
现在,你可以通过访问http://Your_IP:Tomcat_Port/Your_Project访问你的项目了。如果一切顺利,你将看到那绚烂的胜利之光照耀在你的项目之上!
386 41