热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java函数式编程要点总结

函数式编程并不是Java新提出的概念,其与指令编程相比,强调函数的计算比指令的计算更重要;与过程化编程相比,其中函数的计算可以随时调用。Java8新引入函数式编程方式,大大的提高了

一、函数式概念

函数式编程是一种结构化编程的范式,主要思想是把运算过程尽量写成系列嵌套的函数调用。函数编程的概念表述带有很抽象的感觉,可以基于案例看:

public class Function01 {
    public static void main(String[] args) {
        // 运算:(x+y)* c
        int x1 = 2 ;
        int y1 = 3 ;
        int c1 = 4 ;
        int sum1 = x1 + y1 ;
        int res1 = sum1 * c1 ;
        System.out.println("res1 = "+res1);
    }
}

这里基于过程的方式做计算,上面的代码块着重在描述程序执行过程。

在看基于函数的方式解决方法:

public class Function02 {
    public static void main(String[] args) {
        // 函数式计算
        System.out.println("func01 = "+func01(2,3,4));
    }
    private static int func01 (int x,int y,int c){
        return (x+y)*c;
    }
}

函数式编程的核心要素:传入参数,执行逻辑,返回值,也可以没有返回值。

函数式的编程风格侧重描述程序的执行逻辑,不是执行过程。

同上面计算过程相比,函数式编程也减少很多临时变量的创建,代码风格也变的简洁清楚。

二、函数与方法

在Java语言中有函数式编程风格,但是Java代码中没有函数的说法,而是称为:方法;

public class Function03 {
    public static void main(String[] args) {
        Func03 func03 = new Func03();
        func03.add(2);
        System.out.println(func03.res1);
    }
}
class Func03 {
    public int res1 = 0 ;
    public void add (int a1){
        this.res1 = a1 +1 ;
    }
}

类定义引用数据类型,类实例化后的对象可以调用类内部的方法和数据,这是最直观的感觉。

但是方法又有静态和非静态的区别,静态方法属于类所有,类实例化前即可使用。

非静态方法可以访问类中的任何成员变量和方法,并且必须是类实例化后的对象才可以调用。

三、JDK函数基础

1、Lambda表达式

Lambda表达式也可称为闭包,是推动Java8发布的最重要新特性,允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

这里就很鲜明的对比Lambda表达式语法和传统用法。

public class Lambda01 {
    interface LambdaOpera {
        int operation(int a, int b);
    }
    public static void main(String[] args) {
        LambdaOpera lambdaOpera = new LambdaOpera(){
            @Override
            public int operation(int a, int b) {
                return a * b ;
            }
        };
        System.out.println(lambdaOpera.operation(3,2));
        LambdaOpera lambdaOpera01 = (int a, int b) -> a + b;
        LambdaOpera lambdaOpera02 = (int a, int b) -> a - b;
        System.out.println(lambdaOpera01.operation(3,2));
        System.out.println(lambdaOpera02.operation(3,2));
    }
}

在看一个直观的应用案例,基于Lambda的方式创建线程,可以使代码变的更加简洁紧凑:

public class Lambda02 {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 2; i++) {
                    System.out.println(i);
                }
            }
        }).start();
        // 对比 Lambda 方式
        new Thread(() -> {
            for (int i = 0; i < 2; i++) {
                System.out.println(i);
            }
        }).start();
    }
}

在看一下Runnable接口的结构:

FunctionalInterface标记在接口上,表示该接口是函数式接口,并且该接口只包含一个抽象方法,

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Lambda表达式本身可以理解为就是一个接口的实现过程,这里runnable就是完整的Lambda表达式声明:

public class Lambda04 {
    public static void main(String[] args) {
        Runnable runnable = () -> {
            System.out.println("run one...");
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

Lambda表达式最直观的作用就是使得代码变得异常简洁,并且可以作为参数传递。

2、函数式接口

Lambda表达式虽然有很多优点,但是使用的时候需要定义一些接口用来完成编码,这样又使得表达式又变得重量级,Java8自身已经提供几个常见的函数式接口。

  • Function:输入一个参数,返回一个结果;
  • Consumer:输入一个参数,不返回结果;
  • BiFunction:输入两个参数,返回一个结果;
  • BiConsumer:输入两个参数,不返回任何结果;
public class Lambda05 {
    public static void main(String[] args) {
        Function function01 = x -> x * 2;
        System.out.println(function01.apply(2));
        BiFunction function02 = (x, y) -> x * y;
        System.out.println(function02.apply(2, 3));

        Consumer consumer01 = msg -> System.out.println("msg:"+msg);
        consumer01.accept("hello");

        BiConsumer consumer02 = (msg,i)
                -> System.out.println(msg+":"+i);
        consumer02.accept("world",3);
    }
}

如果面对更复杂的业务需求,可以自定义函数式接口去解决。

四、Optional类

1、Null判断

Optional类是Java函数式编程的应用,主要用来解决常见的空指针异常问题。

在Java编程的开发中,很多地方都能常见空指针异常的抛出,如果想避免这个问题就要加入很多判断:

public class Optional01 {
    public static void main(String[] args) {
        User user = new User(1,"hello") ;
        if (user != null){
            if (user.getName() != null){
                System.out.println(user.getName());
            }
        }
    }
}

为了确保程序不抛出空指针这种低级的错误,在程序中随处可以null的判断,代码显然冗余和繁杂。

2、Optional应用

基于Optional类创建的对象可能包含空值和null值,也同样会抛出对应的异常:

public class Optional02 {
    public static void main(String[] args) {
        // NoSuchElementException
        Optional optionalUser = Optional.empty();
        optionalUser.get();
        // NullPointerException
        Optional nullOpt = Optional.of(null);
        nullOpt.get();
    }
}

所以在不明确对象的具体情况下,使用ofNullable()方法:

public class Optional03 {
    public static void main(String[] args) {
        User user = new User(1,"say");
        Optional optionalUser = Optional.ofNullable(user);
        if (optionalUser.isPresent()){
            System.out.println(optionalUser.get().getName());
        }
        User user1 = null ;
        User createUser = Optional.ofNullable(user1).orElse(createUser());
        System.out.println(createUser.getName());
        User user2 = null ;
        Optional.ofNullable(user2).orElseThrow( ()
                -> new RuntimeException());;
    }
    public static User createUser (){
        return new User(2,"hello") ;
    }
}

这样看下来Optional结合链式方法和Lambda表达式就很大程度上简化了应用的代码量:

public class Optional04 {
    public static void main(String[] args) {
        // 1、map转换方法
        User user = new User(99, "Java");
        // user = null ;
        String name = Optional.ofNullable(user)
                .map(u -> u.getName()).orElse("c++");
        System.out.println(name);
        // 2、过滤方法
        Optional optUser01 = Optional.ofNullable(user)
                .filter(u -> u.getName() != null && u.getName().contains("c++"));
        // NoSuchElementException
        System.out.println(optUser01.get().getName());
    }
}

Optional提供null处理的各种方法,可以简洁很多代码判断,但是在使用风格上和之前变化很大。

五、Stream流

如果Optional简化很多Null的判断,那Stream流的API则简化了很多集合的遍历判断,同样也是基于函数式编程。

上述为Stream接口继承关系如图,同样提供一些特定接口和较大的包装接口,通过源码查看,可以看到和函数编程也是密切相关。

public class Stream01 {
    public static void main(String[] args) {
        Stream stream = Stream.of("hello", "java");
        stream.forEach(str -> System.out.print(str+";"));
    }
}

Stream与函数接口结合使用,函数接口又可以使用Lambda表达式进行简化代码。在Java8通过Stream可以大量简化集合使用的代码复杂度。

public class Stream02 {
    public static void main(String[] args) {
        // 1、转换Stream
        List list = Arrays.asList("java+;", "c++;", "net;");
        list.stream();
        // 2、forEach操作
        list.stream().forEach(System.out::print);
        // 3、map映射,输出 3,4
        IntStream.rangeClosed(2,3).map(x->x+1).forEach(System.out::println);
        // 4、filter过滤
        list.stream().filter(str -> str.contains("+")).forEach(System.out::print);
        // 5、distinct去重
        Integer[] arr = new Integer[]{3, 1, 3, 1, 2,4};
        Stream.of(arr).distinct().forEach(System.out::println);
        // 6、sorted排序
        Stream.of(arr).sorted().forEach(System.out::println);
        // 7、collect转换
        List newList = list.stream().filter(str -> str.contains("+"))
                .collect(Collectors.toList());
        newList.stream().forEach(System.out::print);
    }
}

在没有Stream相关API之前,对于集合的操作和遍历都会产生大量的代码,通过Stream相关API集合的函数式编程和Lambda表达式的风格,简化集合很多操作。

六、源代码地址

GitHub・地址
https://github.com/cicadasmile/java-base-parent
GitEE・地址
https://gitee.com/cicadasmile/java-base-parent

以上就是Java 函数式编程要点总结的详细内容,更多关于Java 函数式编程的资料请关注编程笔记其它相关文章!


推荐阅读
  • 本文将继续探讨 JavaScript 函数式编程的高级技巧及其实际应用。通过一个具体的寻路算法示例,我们将深入分析如何利用函数式编程的思想解决复杂问题。示例中,节点之间的连线代表路径,连线上的数字表示两点间的距离。我们将详细讲解如何通过递归和高阶函数等技术实现高效的寻路算法。 ... [详细]
  • 全面解析JavaScript代码注释技巧与标准规范
    在Web前端开发中,JavaScript代码的可读性和维护性至关重要。本文将详细介绍如何有效地使用注释来提高代码的可读性,并探讨JavaScript代码注释的最佳实践和标准规范。通过合理的注释,开发者可以更好地理解和维护复杂的代码逻辑,提升团队协作效率。 ... [详细]
  • 本指南介绍了如何在ASP.NET Web应用程序中利用C#和JavaScript实现基于指纹识别的登录系统。通过集成指纹识别技术,用户无需输入传统的登录ID即可完成身份验证,从而提升用户体验和安全性。我们将详细探讨如何配置和部署这一功能,确保系统的稳定性和可靠性。 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 在多年使用Java 8进行新应用开发和现有应用迁移的过程中,我总结了一些非常实用的技术技巧。虽然我不赞同“最佳实践”这一术语,因为它可能暗示了通用的解决方案,但这些技巧在实际项目中确实能够显著提升开发效率和代码质量。本文将深入解析并探讨这四大高级技巧的具体应用,帮助开发者更好地利用Java 8的强大功能。 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • AIX编程挑战赛:AIX正方形问题的算法解析与Java代码实现
    在昨晚的阅读中,我注意到了CSDN博主西部阿呆-小草屋发表的一篇文章《AIX程序设计大赛——AIX正方形问题》。该文详细阐述了AIX正方形问题的背景,并提供了一种基于Java语言的解决方案。本文将深入解析这一算法的核心思想,并展示具体的Java代码实现,旨在为参赛者和编程爱好者提供有价值的参考。 ... [详细]
  • HBase Java API 进阶:过滤器详解与应用实例
    本文详细探讨了HBase 1.2.6版本中Java API的高级应用,重点介绍了过滤器的使用方法和实际案例。首先,文章对几种常见的HBase过滤器进行了概述,包括列前缀过滤器(ColumnPrefixFilter)和时间戳过滤器(TimestampsFilter)。此外,还详细讲解了分页过滤器(PageFilter)的实现原理及其在大数据查询中的应用场景。通过具体的代码示例,读者可以更好地理解和掌握这些过滤器的使用技巧,从而提高数据处理的效率和灵活性。 ... [详细]
  • 本文深入解析了Spring Cloud路由网关Zuul的核心功能及其典型应用场景。通过对方志朋老师教材的学习和实践,详细探讨了Zuul在微服务架构中的重要作用,包括请求路由、过滤器链管理以及服务动态扩展等关键特性。同时,结合实际案例,展示了Zuul在高并发和复杂业务场景下的应用优势,为读者提供了全面的技术参考。 ... [详细]
  • 如何使用和示例代码解析 org.semanticweb.owlapi.model.OWLSubPropertyChainOfAxiom.getPropertyChain() 方法 ... [详细]
  • 深入探索 JavaScript 中 Array 数组对象的基本操作与应用
    深入探索 JavaScript 中 Array 数组对象的基本操作与应用 ... [详细]
  • RxJava 中 Observable.singleElement() 方法详解与实例代码分析 ... [详细]
  • 在探讨C语言编程文本编辑器的最佳选择与专业推荐时,本文将引导读者构建一个基础的文本编辑器程序。该程序不仅能够打开并显示文本文件的内容及其路径,还集成了菜单和工具栏功能,为用户提供更加便捷的操作体验。通过本案例的学习,读者可以深入了解文本编辑器的核心实现机制。 ... [详细]
  • 如何在Spark数据排序过程中有效避免内存溢出(OOM)问题
    本文深入探讨了在使用Spark进行数据排序时如何有效预防内存溢出(OOM)问题。通过具体的代码示例,详细阐述了优化策略和技术手段,为读者在实际工作中遇到类似问题提供了宝贵的参考和指导。 ... [详细]
author-avatar
手机用户2502927451
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有