JAVA8给我带了什么——流(入门)

Posted 落叶随风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA8给我带了什么——流(入门)相关的知识,希望对你有一定的参考价值。

JAVA8有一个新功能——流。笔者简单的看一下流。然后默默的闭上眼睛。感叹一声:这不是.NET里面的Linq吗?如果你们当中有谁做过.NET程序员的话,对于流的学习其实帮助是很大的。但是要明白你现在是在学JAVA的流。虽然他们的概念是有一点像。可是这也只是对你在理解流上面有一定的帮助。因为JAVA实现的方式却完成不一样子(不入流程序员的个人理解)。

好吧。那么流是什么呢?如果用书里面的方式解释的话,笔者可能也看不懂。做过开发的人员一般都会知道一些SQL语句吧,SELECT语句这个功能。相信大家一定都熟悉吧——SELECT是对数据库的数据进行操作。同样子JAVA也有数据啊。比如集合、数组。那么为什么JAVA不可能实现一套代码式的数据操作。如果这样子不知道大家会不会明白呢?(当然这不是官方,是不入流的程序员这样了理解的)
SQL语句里面有什么——SELECT、FORM、WHERE、ORDER BY、GROUP BY。这些都是对数据库里面数据操作的常规动作。JAVA8的流呢? 即然是流。那么说明必须把对应的数据变成一个流才行。关键方法stream()就是这个作用。 举例子来说明吧。笔者有一组字符数组,笔者相要查找出有含有 r 的字符。

 1 package com.aomi;
 2 
 3 import java.util.Arrays;
 4 import java.util.List;
 5 
 6 public class Main {
 7 
 8     public static void main(String[] args) {
 9         // TODO Auto-generated method stub
10 
11         List<String> datas = Arrays.asList("red", "green", "bule");
12 
13         datas
14         .stream()
15         .filter(s -> s.contains("r"))
16         .forEach(s -> System.out.println(s));
17     }
18 
19 }

运行结果:

让我们想想如果是以前的话,要什么样子去实现呢?

 1 package com.aomi;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 
 7 public class Main {
 8 
 9     public static void main(String[] args) {
10         // TODO Auto-generated method stub
11 
12         List<String> datas = Arrays.asList("red", "green", "bule");
13 
14 //        datas
15 //        .stream()
16 //        .filter(s -> s.contains("r"))
17 //        .forEach(s -> System.out.println(s));
18 
19         List<String> vDatas = new ArrayList<>();
20 
21         for (String str : datas) {
22             if (str.contains("r")) {
23                 vDatas.add(str);
24             }
25         }
26 
27         for (String str : vDatas) {
28             System.out.println(str);
29         }
30 
31     }
32 
33 }

相对以前来讲很直观表现代码的意思。同时代码量又小很多。

  • filter:用于过滤数据的,从下面的代码就可以明白,返回一个boolean型类的结果。
Stream<T> filter(Predicate<? super T> predicate);
  • forEach:循环遍历回来的结果集合。代码看完就知道什么样子用了。
 void forEach(Consumer<? super T> action);

JAVA的代很多都是很人性化的,所以只要从名字就可以明白他大概的功能了。

好了,笔者突然有一个想法——想要把时面的‘r’字符变成‘o’字符。

 1 package com.aomi;
 2 
 3 import java.util.Arrays;
 4 import java.util.List;
 5 
 6 public class Main {
 7 
 8     public static void main(String[] args) {
 9         // TODO Auto-generated method stub
10 
11         List<String> datas = Arrays.asList("red", "green", "bule");
12 
13         datas.stream()
14         .map(s -> s.replace(\'r\', \'o\'))
15         .forEach(s -> System.out.println(s));
16 
17     }
18 
19 }

笔者去掉了filter方法,用了map。运行结果:

  • map:相当于SQL中的 SELECT关键字有一点像。用于把结果变成你希望的样子。看一下代码
 <R> Stream<R> map(Function<? super T, ? extends R> mapper);

是一个function的函数式接口。函数描述符:T -> R。
显示这样子的例子有一点简单。在实际的开发过程中我们往往都是一大波数据对象。这样子笔者定义一个学生类。

package com.aomi;

public class Student {
    private String name;
    private int Sex;
    private String phone;
    private int score;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getSex() {
        return Sex;
    }
    public void setSex(int sex) {
        Sex = sex;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }
    
    
}

在来写一个数据源吧。

 1 package com.aomi;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 
 7 public class Main {
 8 
 9     public static List<Student> getSources()
10     {
11         List<Student> students =new ArrayList<>();
12         
13         Student stu1 = new Student();
14         
15         stu1.setName("lucy");
16         stu1.setSex(0);
17         stu1.setPhone("13700227892");
18         stu1.setScore(9);
19         
20         Student stu2 = new Student();
21         stu2.setName("lin");
22         stu2.setSex(1);
23         stu2.setPhone("15700227122");
24         stu2.setScore(9);
25         
26         Student stu3 = new Student();
27         stu3.setName("lili");
28         stu3.setSex(0);
29         stu3.setPhone("18500227892");
30         stu3.setScore(8);
31         
32         Student stu4 = new Student();
33         
34         stu4.setName("dark");
35         stu4.setSex(1);
36         stu4.setPhone("16700555892");
37         stu4.setScore(6);
38         
39         
40         students.add(stu1);
41         students.add(stu2);
42         students.add(stu3);
43         students.add(stu4);
44         
45         return students;
46     }
47 
48 }

笔者定义了四个学生。这样子时候笔者想看看学分(Score)大于6同学的名字有哪一些。从上面代码我们可以看到除了第四个同学drak之后,其他都是合格的。 让我们看一下代码

 1 package com.aomi;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 import static java.util.stream.Collectors.toList;
 6 
 7 public class Main {
 8 
 9     public static void main(String[] args) {
10         // TODO Auto-generated method stub
11 
12         List<Student> stus = getSources();
13 
14         List<String> names = stus.stream()
15                 .filter(stu -> stu.getScore() > 6)
16                 .map(stu -> stu.getName())
17                 .collect(toList());
18 
19         for (String name : names) {
20             System.out.println(name);
21         }
22 
23     }
24 
25     public static List<Student> getSources() {
26         List<Student> students = new ArrayList<>();
27 
28         Student stu1 = new Student();
29 
30         stu1.setName("lucy");
31         stu1.setSex(0);
32         stu1.setPhone("13700227892");
33         stu1.setScore(9);
34 
35         Student stu2 = new Student();
36         stu2.setName("lin");
37         stu2.setSex(1);
38         stu2.setPhone("15700227122");
39         stu2.setScore(9);
40 
41         Student stu3 = new Student();
42         stu3.setName("lili");
43         stu3.setSex(0);
44         stu3.setPhone("18500227892");
45         stu3.setScore(8);
46 
47         Student stu4 = new Student();
48 
49         stu4.setName("dark");
50         stu4.setSex(1);
51         stu4.setPhone("16700555892");
52         stu4.setScore(6);
53 
54         students.add(stu1);
55         students.add(stu2);
56         students.add(stu3);
57         students.add(stu4);
58 
59         return students;
60     }
61 
62 }

运行结果:

当我们看到这个例子的时候,我们就可以确定map是做什么。就是用于最后确定返回数据类型。在这个代码中。笔者又用到了一个叫collect的方法。

  • collect:用于收集数据的功能。即是把相关的数据汇总成为另一种数据。

笔者传入是toList()方法。把最后数据变成一个集合。这个方法是Collectors类的一个静态方法。当然Collectors类里面有很多静态方法。如果你们去看一下他的代码。你就会发现他的方法名字好像都是在对数据操作的样子。没有错。以后我们开发过程都会用到Collectors类的方法集。
记得引用下面代码

import static java.util.stream.Collectors.toList;

 从上面的几个例子来看。让笔者感觉如下

  • stream相关于SQL里面的FROM
  • filter相当于SQL里面的WHERE.
  • map相当于SQL里面的SELECT

那么其他呢?比如 order by或 group by 。让我们接着看吧。

现在笔者想在按学分(Score)高到低排序并且只显示学生名和学分呢?

package com.aomi;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.List;

public class SMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        List<Student> stus = getSources();

        List<String> names = stus.stream()
                .sorted(comparing(Student::getScore).reversed())
                .map(stu -> "学名:"+stu.getName()+"  学分:"+stu.getScore())
                .collect(toList());

        
        for (String name : names) {
            System.out.println(name);
        }

    }

    public static List<Student> getSources() {
        List<Student> students = new ArrayList<>();

        Student stu1 = new Student();

        stu1.setName("lucy");
        stu1.setSex(0);
        stu1.setPhone("13700227892");
        stu1.setScore(9);

        Student stu2 = new Student();
        stu2.setName("lin");
        stu2.setSex(1);
        stu2.setPhone("15700227122");
        stu2.setScore(9);

        Student stu3 = new Student();
        stu3.setName("lili");
        stu3.setSex(0);
        stu3.setPhone("18500227892");
        stu3.setScore(8);

        Student stu4 = new Student();

        stu4.setName("dark");
        stu4.setSex(1);
        stu4.setPhone("16700555892");
        stu4.setScore(6);

        students.add(stu1);
        students.add(stu2);
        students.add(stu3);
        students.add(stu4);

        return students;
    }
}

运行结果:

关于上面sorted的用法。笔者上面已经讲过了。
现在笔者想看看男女各位的学习情况。又要如何。来分个组吧。

 1 package com.aomi;
 2 
 3 import static java.util.stream.Collectors.groupingBy;
 4 
 5 import java.util.ArrayList;
 6 import java.util.List;
 7 
 8 public class SMain {
 9 
10     public static void main(String[] args) {
11         // TODO Auto-generated method stub
12 
13         List<Student> stus = getSources();
14 
15         stus.stream()
16         .collect(groupingBy(ss -> ss.getSex())).
17         forEach((Integer sex, List<Student> students) -> {
18             System.out.println("sex:" + sex);
19 
20             for (Student student : students) {
21                 System.out.println("name:" + student.getName() + "  score:" + student.getScore());
22             }
23         });
24 
25     }
26 
27 //去掉学生源的方法。太多了影响查看
28 }

结果:

即然都分组了。那就笔者在做一个业务。查看男女个组的人数。

package com.aomi;

import static java.util.stream.Collectors.groupingBy;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class SMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        List<Student> stus = getSources();

        stus.stream().collect(groupingBy(ss -> {
            if (ss.getSex() == 0)
                return "女";
            else
                return "男";
        }, Collectors.counting()))
        .forEach((String sex, Long count) -> {
            System.out.println("sex:" + sex + "  count:" + count);

        });

    }
......
.....//去掉数据源
.....

}

运行结果:

在来一个分组之后,男女个组的总分。

package com.aomi;

import static java.util.stream.Collectors.groupingBy;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class SMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        List<Student> stus = getSources();

        stus.stream().collect(groupingBy(ss -> {
            if (ss.getSex() == 0)
                return "女";
            else
                return "男";
        }, Collectors.summingLong(t -> t.getScore())))
        .forEach((String sex, Long sum) -> {
            System.out.println("sex:" + sex + "  count:" + sum);

        });

    }

    。。。。。
}

运行结果:

通过这俩个例子,我们就可以明白一个道理。groupingBy的第二个参数,是一个任何型类的收集器。也就是说分组之后,你可以在进行对分组之后的结果进处理。

好了。你们有没有感觉跟SQL语句的功能很像呢?如下

  • stream相关于SQL里面的FROM
  • filter相当于SQL里面的WHERE.
  • map相当于SQL里面的SELECT
  • sorted相当于SQL里面的Order BY
  • Collectors.groupingBy相当于SQL里面的GROUP BY
  • Collectors.summingLong相当于SQL里面的SUM函数。只不过他又加了一步结果转为Long类型
  • Collectors.counting相当于SQL里面的COUNT函数

 理解了上面代码的基础用法的概念之后,我们接下要一步步去看看JAVA8流的思想。

以上是关于JAVA8给我带了什么——流(入门)的主要内容,如果未能解决你的问题,请参考以下文章

Java8 Stream流

java8 函数式编程入门官方文档中文版 java.util.stream 中文版 流处理的相关概念

[一] java8 函数式编程入门 什么是函数式编程 函数接口概念 流和收集器基本概念

关于python中pika模块的问题

Java 8 Stream入门

Java 8 Stream入门