欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java Stream函数式编程图文详解(二):管道数据处理

程序员文章站 2022-12-21 13:10:23
一、Java Stream管道数据处理操作 在本号之前发布的文章《Java Stream函数式编程?用过都说好,案例图文详解送给你》中,笔者对Java Stream的介绍以及简单的使用方法给大家做了介绍。在开始本文之前,我们有必要介绍一下这张Java Stream 数据处理过程图,图中主要分三个部分 ......

Java Stream函数式编程图文详解(二):管道数据处理

一、java stream管道数据处理操作

在本号之前发布的文章《java stream函数式编程?用过都说好,案例图文详解送给你》中,笔者对java stream的介绍以及简单的使用方法给大家做了介绍。在开始本文之前,我们有必要介绍一下这张java stream 数据处理过程图,图中主要分三个部分:

Java Stream函数式编程图文详解(二):管道数据处理

  • 将数组、集合类、文本文件转换为管道流(图中的蓝色方块的部分,在本号的上一篇文章中已经给大家介绍过了)
  • java stream管道数据处理操作(也就是下图中中间的虚线内的数据处理操作,本文的主要内容)
  • 管道流处理结果的聚合、累加、计数、转换为集合类等操作(图中的绿色方块部分)

需要注意的是:java stream的中间数据处理操作的输入是一个管道流(stream),输出仍然是一个管道流(stream)。下面我们就来详细的学习一下!在上一篇文章中,我们给大家讲了这样一个例子:

    list<string> namestrs = arrays.aslist("monkey", "lion", "giraffe","lemur");
    
    list<string> list = namestrs.stream()
            .filter(s -> s.startswith("l"))
            .map(string::touppercase)
            .sorted()
            .collect(tolist());
    system.out.println(list);

这个例子完成的功能就是:首先使用stream()函数将数组转换为管道流,然后对管道流中的元素进行过滤filter(),只保留l开头的元素,然后对每一个元素转换为大写(map(string::touppercase)),然后排序sorted(),最终转换为list类型。经过处理之后的输出结果是: [lemur, lion].在上面的例子中,filter()、map()、sorted()都属于中间数据处理操作,下面就给大家讲解一下这些函数的详细用法。

二、filter管道数据过滤

根据笔者的的经验,filter()是stream api最有用的操作之一,它可以过滤掉不符合条件的元素。下面的代码过滤掉管道中的不是以l开头的字符串元素。处理完成之后,管道中剩下的元素是:[lion, lemur]

     stream<string> startswitht = stream.of("monkey", "lion", "giraffe", "lemur")
     .filter(s -> s.startswith("l"));

如果没有学过lambda表达式的同学,可能对上面的代码感到困惑。其实很简单,lambda表达式用来表达函数,箭头左侧是参数,箭头右侧是函数体。函数的参数类型和返回值类型,会根据上下文做自动化的判断,不用你管。上文中的lambda表达式写成函数是这样的

    public static boolean filterupperl(string str){
        return str.startswith("l");
    }
    
    //.filter(bootlaunchapplicationtests::filterupperl)

我甚至见过有的人排斥使用lambda表达式,说这种语法使代码的可读性下降。这个怎么说呢,如果一篇专业期刊中包含英语专业名词与引用,而读者恰巧不会英语就不想读了,我觉得这不是文章的问题,而是读者的问题。而且lamdba表达式在各种编程语言里面得到广泛的使用,提高编码效率。其实很简单:箭头左侧是参数,箭头右侧是函数体,你已经学会了!

三、limit与skip管道数据截取

     stream<string> startswitht = stream.of("monkey", "lion", "giraffe", "lemur").limit(2);
     stream<string> startswitht = stream.of("monkey", "lion", "giraffe", "lemur").skip(2);
  • limt方法传入一个整数n,用于截取管道中的前n个元素。经过管道处理之后的数据是:[monkey, lion]。
  • skip方法与limit方法的使用相反,用于跳过前n个元素,截取从n到末尾的元素。经过管道处理之后的数据是: [giraffe, lemur]

四、distinct元素去重

我们还可以使用distinct方法对管道中的元素去重,涉及到去重就一定涉及到元素之间的比较,distinct方法时调用object的equals方法进行对象的比较的,如果你有自己的比较规则,可以重写equals方法。

    stream<string> uniqueanimals = stream.of("monkey", "lion", "giraffe", "lemur", "lion")
            .distinct();

上面代码去重之后的结果是: ["monkey", "lion", "giraffe", "lemur"]

五、sorted排序

默认的情况下,sorted是按照字母的自然顺序进行排序。如下代码的排序结果是:[giraffe, lemur, lion, monkey],字数按顺序g在l前面,l在m前面。第一位无法区分顺序,就比较第二位字母。

    stream<string> alphabeticorder = stream.of("monkey", "lion", "giraffe", "lemur")
            .sorted();

有的时候,我们希望排序的规则能够自定义,这就需要使用到comparator。有的朋友这里可能忘了,可以自行回顾一下java基础的comparator和comparable接口。下面的代码是根据字符串的长度排序,排序结果是:[lion, lemur, monkey, giraffe]

    stream<string> lengthorder = stream.of("monkey", "lion", "giraffe", "lemur")
            .sorted(comparator.comparing(string::length));

六、map数据转换处理

map()函数的作用是将管道流中的每一个元素,以某种规则转换为另外一个元素。下面代码处理过的管道中的元素为: [monkey, lion, giraffe, lemur],所有元素的字母全部小写。

    stream<string> lowercase = stream.of("monkey", "lion", "giraffe", "lemur")
            .map(string::tolowercase);
    
    //这两种写法的实现效果是一样的,一个是lambda表达式,一个是函数引用的方式
    stream<string> lowercase = stream.of("monkey", "lion", "giraffe", "lemur")
            .map(s -> s.tolowercase());

map()函数不仅可以处理数据,还可以转换数据的类型。如下:

    intstream lengths = stream.of("monkey", "lion", "giraffe", "lemur")
            .maptoint(string::length);

上面代码的处理结果是:[6, 4, 7, 5],规则是字符串的长度。将管道流的字符串,使用maptoint方法,以string::length为规则进行转换。当然除了maptoint,还为我们提供了maptodouble()和maptolong()方法。我们可以通过自定义转换规则函数,返回int、double、long类型的返回值。

期待您的关注