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 函数式编程入门官方文档中文版 java.util.stream 中文版 流处理的相关概念