千家信息网

Java8函数式编程方法是什么

发表于:2024-11-11 作者:千家信息网编辑
千家信息网最后更新 2024年11月11日,这篇"Java8函数式编程方法是什么"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"J
千家信息网最后更新 2024年11月11日Java8函数式编程方法是什么

这篇"Java8函数式编程方法是什么"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"Java8函数式编程方法是什么"文章吧。

    什么是函数式编程

    函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。 函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数! 函数式编程最早是数学家阿隆佐·邱奇研究的一套函数变换逻辑,又称Lambda Calculus(λ-Calculus),所以也经常把函数式编程称为Lambda计算。

    Java8内置了一些常用的方法接口FunctionalInterface

    这种接口只定义了一个抽象方法,并且用@FunctionalInterface注解标记,如Predicate,Consumer,Function,Supplier,Comparator等等,这些都属于java.util.function包中

    @FunctionalInterfacepublic interface Predicate {    boolean test(T t);}@FunctionalInterfacepublic interface Consumer {    void accept(T t);}// 省略不贴了

    他们的特点是定义了函数的入参以及返回值,当使用时传入满足函数接口定义的表达式,即可通过编译器检查,下面会介绍函数接口和对应的4种使用方式

    通过一个示例来看看使用函数式和不使用的区别,需求是要有一个函数,传入一个List,筛选出单数的项,另一个则筛选出双数的项,先看看不使用函数式的写法

        // 筛选出单数的方法    public static List filterSingular(List list) {        List result = new ArrayList<>();        for (Integer item : list) {            if (item % 2 != 0) {                result.add(item);            }        }        return result;    }    // 筛选出双数的方法    public static List filterEven(List list) {        List result = new ArrayList<>();        for (Integer item : list) {            if (item % 2 == 0) {                result.add(item);            }        }        return result;    }

    定义方法后调用,预期效果输出[1,3,5,7]和[2,4,5]

            List targetList = new ArrayList() {            {                this.add(1);                this.add(2);                this.add(3);                this.add(4);                this.add(5);                this.add(6);                this.add(7);            }        };        List singularList = filterSingular(targetList);        List evenList = filterEven(targetList);        System.out.println(singularList);        System.out.println(evenList);

    但其实这两个筛选函数,唯一区别只是判断条件的不同,这时候就可以将这个条件抽象成一个函数接口去编写,Predicate接口的test定义文章开头就有,传入一个泛型类型,返回一个boolean,改写下filter的代码

        public static List filter(List list,Predicate predicate) {        List result = new ArrayList<>();        for (Integer item : list) {            if (predicate.test(item)) {                result.add(item);            }        }        return result;    }

    将函数改造成了除了传入目前List外,还要传入一个实现了Predicate接口的实例对象,只需要传入满足函数定义入参和出参,就能通过编译,下面介绍4种这个函数的使用方式

    • 使用传统的匿名内部类,在java8之前只能这么操作

            List singularList = filter(targetList, new Predicate() {            @Override            public boolean test(Integer integer) {                return integer % 2 != 0;            }        });        System.out.println(singularList);
    • 使用lambda表达式格式如下()->{},()的是方法列表,->{}是方法体,由于目前只有一个参数,并且参数类型是可以推断出来的,所以类型和()可以不写,方法体只有一句,{}也可以不写,不推荐在方法体中写过长的代码,应保证可读性

            List singularList2 = filter(targetList, integer -> integer % 2 != 0);        // 下面是完整写法        // List singularList3 = filter(targetList, (Integer integer) -> {        //    return integer % 2 != 0;        // });

    可以使用的原因,lambda表达式满足传入Integer返回一个boolean的抽象操作,可以自动转化为函数接口

    • 静态方法引用,这里定义了一个静态方法,也可以自动的转化为函数接口,使用时需要用双冒号语法

        private static boolean integerWithSingular (Integer haha){        return haha % 2 != 0;    }

    使用静态方法引用,Cn是所在类名,这种方式对比lambda表达式可以让可读性进一步提高,因为方法有名字,可以通过名字去判断在执行什么操作,并且更适合编写更多的逻辑

        List singularList3 = filter(targetList, Cn::integerWithSingular);
    • 实例方法,因为任何实例方法,第一个参数永远都是一个隐藏的指针this指向当前实例,由于上面例子泛型传入的是Integer类型,需要改写下预期才能演示,先声明一个类,并且有一个实例方法是完成传入Test类型返回boolean的映射

    public class Test {    private long id;        public Test(long id) {        this.id = id;    }        private boolean integerWithSingular(){        return this.id % 2 != 0;    }}

    将filter函数的Integer类型全换成Test类型

        public static List filter(List list, Predicate predicate) {        List result = new ArrayList<>();        for (Test item : list) {            if (predicate.test(item)) {                result.add(item);            }        }        return result;    }

    下面的调用中,传入类名::实例方法名实现的效果是等价的

        ArrayList targetList = new ArrayList() {        {            this.add(new Test(1));            this.add(new Test(2));        }    };    filter(targetList,Test::integerWithSingular);

    任何只包含一个抽象方法的接口都可以被自动转换成函数接口,自己定义的接口没有标注@FunctionalInterface标注也可以

    用的比较多的函数接口

    • Consumer 输入一个对象,输出是空的,相当于消费掉传入的对象,ArrayList的forEach方法使用了Consumer

        // ArrayList的forEach方法源码    @Override    public void forEach(Consumer action) {        Objects.requireNonNull(action);        final int expectedModCount = modCount;        @SuppressWarnings("unchecked")        final E[] elementData = (E[]) this.elementData;        final int size = this.size;        for (int i=0; modCount == expectedModCount && i < size; i++) {            action.accept(elementData[i]);        }        if (modCount != expectedModCount) {            throw new ConcurrentModificationException();        }    }
    • Function更加接近于函数的定义,用于将一个类型变换成另一个类型,如数学中的函数把X变成Y,函数接口的定义如下,还是以刚才编写的Test类为理解,再编写一个map方法

        public static String map(Test test, Function function) {        return function.apply(test);    }

    只要满足传入一个Test类型,返回一个String类型的东西都可以被自动转换

            map(new Test(1),test -> "name");                // 如果Test类型还有一个属性为String的name和对应的getter方法,可以写成下面这种实例方法引用        // map(new Test(2), Test::getName);
    • Supplier和Consumer是对立者,Consumer消费,Supplier提供,从虚空中提供一个东西

        public static Object create(Supplier supplier){        return supplier.get();    }

    只要满足凭空冒出一个东西的条件即可

        create(Object::new);    // new的作用也是从虚无创造出一个对象,所以可以这么写    create(() -> "supplier");    create(() -> new Test(1));

    最后再介绍函数式编程在排序中的使用

        // Collections.sort的静态方法定义    public static  void sort(List list, Comparator c) {        list.sort(c);    }    // Comparator.comparing的静态方法定义    // 理解成需要传入一个T类型映射到U类型的形式即可    // 对应着示例就是传入一个Test,返回一个实现了Comparable接口的对象(如Integer,String...)    public static > Comparator comparing(            Function keyExtractor)    {        Objects.requireNonNull(keyExtractor);        return (Comparator & Serializable)            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));    }

    下面是爽快时间

        // 使用简短的代码就能实现按对象中某个字段去排序    public static void main(String[] args) {        ArrayList tests = new ArrayList() {            {                this.add(new Test(2, "abc"));                this.add(new Test(1, "efg"));            }        };        // 现在Test实例的id字段排序,再将数组反转,然后再按照name字段排序        Collections.sort(tests, Comparator.comparing(Test::getId)                .reversed()                .thenComparing(Test::getName));        System.out.println(tests);    }

    以上就是关于"Java8函数式编程方法是什么"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。

    函数 方法 接口 类型 编程 实例 对象 内容 就是 静态 参数 表达式 选出 排序 输出 东西 代码 变量 字段 文章 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 华中科技大学互联网创新创业 nbsp 能存入数据库吗 加强网络安全意识画 cs连接任何服务器失败 中国工业普查数据库 数据库查询时Null为零 kis数据库未启动 无锡网络安全准入控制报价 企业的服务器数字证书申请流程 软件开发量评估 服务器怎么测试put 连接数据库要准备哪几个app 触摸屏有没有实时数据库 数据库怎么往表里添加数据 国家网络安全股票龙头一览表 电脑电子软件开发是干什么的 国家网络安全周电脑关机 西安网络安全宣传周会场 边缘计算服务器市场机遇 无锡可视化智慧学校软件开发 国际互联网科技情报工作 怎么修改数据库默认字符 迁安电子网络技术答疑解惑 海南中国移动dns服务器云主机 深入贯彻落实网络安全法 上海赢势网络技术 巨杉软件开发有限公司面试 海思软件开发 前程无忧 卫生系统网络安全自查表 中国使用的互联网服务器在哪里
    0