关于java:Java基础篇05函数式编程概念和应用

5次阅读

共计 5701 个字符,预计需要花费 15 分钟才能阅读完成。

本文源码:GitHub·点这里 || GitEE·点这里

一、函数式概念

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

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<Integer, Integer> function01 = x -> x * 2;
        System.out.println(function01.apply(2));
        BiFunction<Integer, Integer, Integer> function02 = (x, y) -> x * y;
        System.out.println(function02.apply(2, 3));

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

        BiConsumer<String,Integer> 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<User> optionalUser = Optional.empty();
        optionalUser.get();
        // NullPointerException
        Optional<User> nullOpt = Optional.of(null);
        nullOpt.get();}
}

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

public class Optional03 {public static void main(String[] args) {User user = new User(1,"say");
        Optional<User> 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<User> 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<String> 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<String> 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<String> 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 根底】【设计模式】【构造与算法】【Linux 零碎】【数据库】

【分布式架构】【微服务】【大数据组件】【SpringBoot 进阶】【Spring&Boot 根底】

【数据分析】【技术导图】【职场】

正文完
 0