转载自 https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/index.html
一、什么是流
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。
而和迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。
二、流的分类
1、Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
2、Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
二、流的操作
流常用的操作可归为以下:
1、Intermediate:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
2、Terminal :forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
3、Short-circuiting:anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit
三、Stream的使用
public class Person {
private String name;
private Integer age;
private String city;
private String gender;
public Person(String name, Integer age, String city,String gender) {
this.name = name;
this.age = age;
this.city = city;
this.gender = gender;
}
}
public class StreamTest {
private static List<Person> personList = new ArrayList<>();
@Before
public void setUp(){
Person person1 = new Person("Lisa" ,19,"杭州","女");
Person person2 = new Person("Jacob", 24,"杭州","男");
Person person3 = new Person("Bob", 15,"杭州","男");
Person person4 = new Person("Michael",20,"杭州","男");
Person person5 = new Person("Michael", 22,"杭州","男");
Person person6 = new Person("Kate", 20,"杭州","女");
personList.add(person1);
personList.add(person2);
personList.add(person3);
personList.add(person4);
personList.add(person5);
personList.add(person6);
personList.add(person6);
}
@Test
public void testIntermediate(){
System.out.println("年龄加1");
personList.stream().map(person -> {
person.setAge(person.getAge() + 1);
return person;
}).forEach(System.out::println);
System.out.println("------------------分界线-----------------");
System.out.println("年龄加1");
personList.stream().peek(person -> person.setAge(person.getAge() + 1 )).forEach(System.out::println);
System.out.println("------------------分界线-----------------");
System.out.println("只打印年龄");
personList.stream().mapToInt(Person::getAge).forEach(System.out::println);
System.out.println("------------------分界线-----------------");
System.out.println("只打印年龄大于25的人");
personList.stream().filter(person -> person.getAge() > 25).forEach(System.out::println);
System.out.println("------------------分界线-----------------");
System.out.println("去掉重复的人");
personList.stream().distinct().forEach(System.out::println);
System.out.println("------------------分界线-----------------");
System.out.println("按年龄排序");
personList.stream().sorted((p1,p2) -> {
if (p1.getAge() >= p2.getAge()){
return 0;
}else {
return -1;
}
}).forEach(System.out::println);
System.out.println("------------------分界线-----------------");
System.out.println("只打印前两个");
personList.stream().limit(2).forEach(System.out::println);
System.out.println("------------------分界线-----------------");
System.out.println("跳过指定元素");
personList.stream().skip(1).forEach(System.out::println);
}
@Test
public void testTerminal(){
Person defaultPerson = new Person("default",0,"default","default");
System.out.println("------------------分界线-----------------");
System.out.println("获取年龄最大的人");
Person person = personList.stream().reduce((person1, person2) -> {
if (person1.getAge() > person2.getAge()){
return person1;
}else {
return person2;
}
}).orElse(defaultPerson);
System.out.println(person);
System.out.println("------------------分界线-----------------");
System.out.println("stream转换成集合");
personList.stream().collect(Collectors.toList()).forEach(System.out::println);
System.out.println("------------------分界线-----------------");
System.out.println("查找最小年龄的人");
person = personList.stream().min((o1, o2) -> {
if (o1.getAge() > o2.getAge()){
return 1;
}else {
return -1;
}
}).orElse(defaultPerson);
System.out.println(person);
System.out.println("------------------分界线-----------------");
System.out.println("查找最大年龄的人");
person = personList.stream().max((o1, o2) -> {
if (o1.getAge() > o2.getAge()){
return 1;
}else {
return -1;
}
}).orElse(defaultPerson);
System.out.println(person);
System.out.println("------------------分界线-----------------");
System.out.println("流的长度");
long size = personList.stream().count();
System.out.println(size);
System.out.println("------------------分界线-----------------");
System.out.println("是否存在年龄位20的人");
boolean result = personList.stream().anyMatch(person1 -> person1.getAge() == 20);
System.out.println(result);
System.out.println("------------------分界线-----------------");
System.out.println("所有年龄是否都为20");
result = personList.stream().allMatch(person1 -> person1.getAge() == 20);
System.out.println(result);
System.out.println("------------------分界线-----------------");
System.out.println("所有年龄不存在20的人");
result = personList.stream().noneMatch(person1 -> person1.getAge() == 20);
System.out.println(result);
System.out.println("------------------分界线-----------------");
System.out.println("在并行过程中找到满足条件的人");
person = personList.stream().filter(person1 -> person1.getAge() > 19).findFirst().orElse(defaultPerson);
System.out.println(person);
System.out.println("------------------分界线-----------------");
System.out.println("在并行过程中找到满足条件的人");
person = personList.stream().filter(person1 -> person1.getAge() > 19).findAny().orElse(defaultPerson);
System.out.println(person);
}
`