JAVA8 新特性 函数式编程

import com.google.common.collect.Lists;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;


class MyClass {
    public static MyClass init(final Supplier supplier) {
        return supplier.get();
    }

    public static void staticFunction(MyClass myClass) {
        System.out.println("static function");
    }

    public void nonStaticFunctionWithParam(final MyClass myClass) {
        System.out.println("non static function with param");
    }

    public void nonStaticFunctionWithoutParam() {
        System.out.println("non static function without param");
    }
}

class Entity {

    private MyClass myClass;

    Entity() {
        myClass = null;
    }

    public MyClass getMyClass() {
        return myClass;
    }

    public void setMyClass(MyClass myclass) {
        this.myClass = myclass;
    }
}


public class Test {

    public static void main(String[] args) throws Throwable {

        /**
         * “Lambda 表达式”(lambda expression)是一个匿名函数,即没有函数名的函数。
         * Lambda 表达式由三个部分组成:
         * 第一部分为一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数;
         * 第二部分为一个箭头符号:->;
         * 第三部分为方法体,可以是表达式和代码块
         * 以下是lambda表达式的重要特征:
         * 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
         * 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
         * 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
         * 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
         * java 8 内部Lambda 表达式的实现方式在本质是以匿名内部类的形式的实现的
         * */
        MyFunction myFunction = new MyFunction() {
            @Override
            public double function(int a, int b) {
                return a + b;
            }
        };
        double q = doFunction(0,0,myFunction);
        // 将函数作为参数传入,此处使用() -> {}代替内部类
        double v = doFunction(1, 3, (a, b) -> a * b);
        double w = doFunction(2,4, Integer::sum);

        /**
         * 方法引用
         * 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。
         * 方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。
         * 计算时,方法引用会创建函数式接口的一个实例。
         * 方法引用通过方法的名字来指向一个方法
         * 方法引用可以使语言的构造更紧凑简洁,减少冗余代码
         * 方法引用使用一对冒号 ::
         * */
        ArrayList testClass = new ArrayList<>();

        /** 构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下: */
        final MyClass myClass = MyClass.init(MyClass::new);
        testClass.stream().toArray(MyClass[]::new);

        /** 静态方法引用:它的语法是Class::static_method,实例如下: */
        // 等价于 (param) -> System.out.println(param)
        PrintFunction printFunction = System.out::println;
        printFunction.print("static");
        // 等价于 (i) -> MyClass.staticFunction(i)
        testClass.forEach(MyClass::staticFunction);

        /** 特定类的任意对象的方法引用:它的语法是Class::method实例如下: */
        // 等价于 (param) -> param.isEmpty()
        NonStaticFunction test = String::isEmpty;
        test.isEmpty("");
        // 等价于 (param) -> param.nonStaticFunctionWithoutParam()
        NonStaticFunction2 nonStatic = MyClass::nonStaticFunctionWithoutParam;
        nonStatic.nonStaticFunction(myClass);

        /** 特定对象的方法引用:它的语法是instance::method实例如下:*/
        // 等价于 (i) -> myClass.nonStaticFunctionWithParam(i)
        testClass.forEach(myClass::nonStaticFunctionWithParam);
        List stringList = new ArrayList<>();
        // 等价于 (i) -> "str".split(i)
        stringList.forEach("str"::split);

        /**
         * 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
         * 函数式接口可以被隐式转换为 lambda 表达式。
         * Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上
         *
         * */

        /** 可以使用Lambda表达式来表示该接口的一个实现 */
        PrintFunctionalInterface functionalInterface = (param) -> System.out.println(param.toString());
        functionalInterface.print("msg");
        doFunctionInterface("msg",(param) -> System.out.println(param.toString()));

        /**
         * 函数式接口可以对现有的函数友好地支持 lambda。
         * JDK 1.8 之前已有的函数式接口:
         * java.lang.Runnable、java.util.concurrent.Callable、java.security.PrivilegedAction、java.util.Comparator、
         * java.io.FileFilter、java.nio.file.PathMatcher、java.lang.reflect.InvocationHandler、
         * java.beans.PropertyChangeListener、java.awt.event.ActionListener、javax.swing.event.ChangeListener
         * */
        new Thread(() -> System.out.println("thread start")).start();
        // 等价于
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread start");
            }
        }).start();

        /**
         * JDK 1.8 新增加的函数接口:
         * java.util.function 它包含了很多类,用来支持 Java的 函数式编程
         * */
        String s = useIntFunction(2, i -> "114514".substring(i));
        List intList = intFunctionTest(Lists.newArrayList(1, 2, 3, 4, 5), e -> e * e);

        /**
         * Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
         * Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
         * Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
         * 这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
         * 元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
         * Stream(流)是一个来自数据源的元素队列并支持聚合操作
         * 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
         * 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
         * 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
         * 和以前的Collection操作不同, Stream操作还有两个基础的特征:
         * Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
         * 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
         * */
        List list = Lists.newArrayList(1, 2, 3, 4, 5);
        Integer[] array = new Integer[] {1, 2, 3, 4, 5};

        /** 生成流 */
        Stream stream = list.stream();
        stream = list.parallelStream();
        stream = Stream.of(1,2,3,4);
        stream = Stream.of(array);
        stream = Arrays.stream(array);
        // 无限
        stream = Stream.iterate(1, item -> item + 1);
        // stream = Stream.generate(java.lang.Math::random)
        // 空
        stream = Stream.empty();

        /**
         * 中间操作:
         * 无状态:(一次操作,不能保存数据。线程安全)
         * unordered() filter() map[ToXXX]() flatMap[ToXXX]() peek()
         * 有状态:(有数据存储功能,线程不安全)
         * distinct() sorted() limit() skip()
         * 结束操作:
         * 非短路操作:
         * forEach() forEachOrdered() toArray() reduce() collect() max() min() count()
         * 短路操作:
         * anyMatch() allMatch() noneMatch() findFirst() findAny()
         * */
        // unordered():消除流中必须保持的有序约束
        // filter():对原Stream按照指定条件过滤,在新建的Stream中,只包含满足条件的元素,将不满足条件的元素过滤掉
        Stream.of(1,2,3,4).filter(i -> i <= 3).forEach(System.out::print);System.out.println();
        // map(): 将对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素
        Stream.of(1,2,3,4).map(i -> i * i).forEach(System.out::print);System.out.println();
        // flatMap():与map方法类似,但该换转函数的对象是一个Stream,也不会再创建一个新的Stream,而是将原Stream的元素取代为转换的Stream
        Stream.of(1,2,3,4).flatMap(i -> Stream.of(i * i)).forEach(System.out::print);System.out.println();
        // peek():生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数,并且消费函数优先执行
        Stream.of(1,2,3,4).peek(i -> System.out.println(i * 10)).forEach(System.out::print);System.out.println();
        // distinct():达到去除掉原Stream中重复的元素,生成的新Stream中没有没有重复的元素。
        Stream.of(1,1,4,5,1,4).distinct().forEach(System.out::print);System.out.println();
        // sorted():将对原Stream进行排序,返回一个有序列的新Stream
        Stream.of(1,1,4,5,1,4).sorted((o1, o2) -> o2 - o1).forEach(System.out::print);System.out.println();
        // limit():将截取原Stream,截取后Stream的最大长度不能超过指定值N
        Stream.of(1,1,4,5,1,4).limit(3).forEach(System.out::print);System.out.println();
        // skip():将过滤掉原Stream中的前N个元素,返回剩下的元素所组成的新Stream。
        Stream.of(1,1,4,5,1,4).skip(3).forEach(System.out::print);System.out.println();
        // forEach():遍历Stream中的所元素
        Stream.of(1,1,4,5,1,4).forEach(System.out::print);System.out.println();
        // forEachOrdered():如果Stream预先设定了顺序,会按照预先设定的顺序执行
        Stream.of(1,1,4,5,1,4).forEachOrdered(System.out::print);System.out.println();
        // toArray():返回一个数组
        Integer[] streamResult = Stream.of(1, 1, 4, 5, 1, 4).toArray(Integer[]::new);
        Object[] streamObjectResult = Stream.of(1, 1, 4, 5, 1, 4).toArray();
        // reduce():对流进行运算获取结果 BinaryOperator 输入两个数输出一个数 类型相同 依次对前一次操作结果和流下一个元素执行操作 identity作为第零次结果
        System.out.println(Stream.of(1,10,100,1000,10000,100000).reduce(1, (integer, integer2) -> integer - integer2).toString());
        // collect(): 需要借助Collectors工具类(Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串) 返回一个Collector或者Optional
        ArrayList collect = Stream.of(1, 3, 4, 5).collect(ArrayList::new, ((integers, integer) -> {
            if (integer % 2 != 0) integers.add(integer);
        }), ArrayList::addAll);
        System.out.println(collect.toString());
        HashMap count = Stream.of(1, 1, 4, 5, 1, 4).collect(Collectors.groupingBy(x -> 2 * x, HashMap::new, Collectors.counting()));
        System.out.println(count.toString());
        // max():根据指定的Comparator,返回一个Optional,该Optional中的value值就是Stream中最大的元素。
        System.out.println(Stream.of(1, 1, 4, 5, 1, 4).max((x1, x2) -> x2 - x1).get());
        // min():根据指定的Comparator,返回一个Optional,该Optional中的value值就是Stream中最小的元素
        System.out.println(Stream.of(1, 1, 4, 5, 1, 4).min(Comparator.comparingInt(x -> x)).get());
        // count()
        System.out.println(Stream.of(1, 1, 4, 5, 1, 4).count());
        // allMatch():用于判断Stream中的元素是否全部满足指定条件。如果全部满足条件返回true,否则返回false
        System.out.println(Stream.of(1, 1, 4, 5, 1, 4).allMatch(x -> x < 4));
        // anyMatch()用于判断Stream中的是否有满足指定条件的元素
        System.out.println(Stream.of(1, 1, 4, 5, 1, 4).anyMatch(x -> x >= 5));
        // noneMatch() 判断是否全部不满足条件
        System.out.println(Stream.of(1, 1, 4, 5, 1, 4).noneMatch(x -> x > 5));
        // findAny()用于获取含有Stream中的某个元素的Optional,如果Stream为空,则返回一个空的Optional。
        System.out.println(Stream.of(1, 1, 4, 5, 1, 4).findAny());
        // findFirst操作用于获取含有Stream中的第一个元素的Optional,如果Stream为空,则返回一个空的Optional。
        System.out.println(Stream.of(1, 1, 4, 5, 1, 4).findFirst());

        /**
         * Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
         * Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
         * Optional 类的引入很好的解决空指针异常。
         * */
        Optional optional = Optional.empty();
        List integerList = new ArrayList<>();

        /**
         * Optional 的三种构造方式: Optional.of(obj), Optional.ofNullable(obj) 和明确的 Optional.empty()
         * Optional.of(obj): 它要求传入的 obj 不能是 null 值的, 否则直接报 NullPointerException 异常。
         * Optional.ofNullable(obj): 它以一种智能的, 宽容的方式来构造一个 Optional 实例. 来者不拒, 传 null 进到就得到 Optional.empty(), 非 null 就调用 Optional.of(obj).
         * Optional.empty():返回一个空的 Optional 对象
         * */
        optional = Optional.ofNullable(null);
        optional = Optional.of(new Entity());

        /** ifPresent:调用其他方法返回一个集合,在不通过 if 判断是否为 null 就可以放心的遍历 */
        Optional.ofNullable(integerList).ifPresent(e -> e.forEach(System.out::println));

        /** filter 满足条件就会返回整个集合,否则返回空集合*/
        Optional.of(Lists.newArrayList(1,2,3,4,5)).filter(integers -> integers.stream().allMatch((i -> i < 4))).ifPresent(e -> e.forEach(System.out::println));

        /** orElse:在目标集合对象为 null 的时候可以设定默认值 */
        String nullStr = null;
        System.out.println(Optional.ofNullable(nullStr).orElse("124"));

        /** orElseGet: 会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果*/
        System.out.println(Optional.ofNullable(nullStr).orElseGet(() -> MyClass.init(MyClass::new).toString()));

        /** orElseThrow() 它会在对象为空的时候抛出异常,而不是返回备选的值 */
        System.out.println(Optional.ofNullable("11").orElseThrow(IllegalAccessException::new));

        /** map() 对值应用(调用)作为参数的函数,然后将返回的值包装在 Optional 中*/
        System.out.println(Optional.of(Lists.newArrayList(1,2,3,4,5)).map(ArrayList::size).orElse(0));

        /** flatMap() 需要自己手动返回Optional对象*/
        System.out.println(Optional.of(Lists.newArrayList(1,2,3,4,5)).flatMap(integers -> Optional.of(integers.size())).orElse(0));

        /** 判断从数据库取出的对象的属性是否为空 */
        Entity entity = new Entity();
        String orElse = Optional.ofNullable(entity.getMyClass()).map(Object::toString).orElse("123");
        System.out.println(orElse);
    }

    interface PrintFunction {
        void print(String msg);
    }

    interface MyFunction {
        double function(int a,int b);
    }

    private static double doFunction(int a,int b,MyFunction myFunction) {
        return myFunction.function(a,b);
    }

    /**    */
    interface NonStaticFunction {
        boolean isEmpty(String a);
    }

    interface NonStaticFunction2 {
        void nonStaticFunction(MyClass myClass);
    }

    /**    */
    @FunctionalInterface
    interface PrintFunctionalInterface {
        void print(T msg);
    }

    private static void doFunctionInterface(Object msg,PrintFunctionalInterface functionalInterface) {
        functionalInterface.print(msg);
    }

    private static String useIntFunction(Integer n,IntFunction intFunction) {
        return intFunction.apply(n);
    }

    private static List intFunctionTest(List list, IntFunction integerIntFunction) {
        List res = new ArrayList<>();
        list.forEach(i-> res.add(integerIntFunction.apply(i)));

        return res;
    }

}


你可能感兴趣的:(笔记)