JAVA1.8新特性Stream API的简单使用
list.stream()和list.parallelStream()的区别:stream(),单线程操作,虽然Stream API支持多线程操作集合,但是普通的stream()并没有提供多线程操作,实质上还是串行运行,对于遍历集合来说,它和迭代器,for循环相同,效率没有太大的区别。而parallelStream()则是多线程操作list,它会把list拆分成几部分,使用多线程并行操作,而至于会产生多少个线程来处理,则和cpu个数有关,一般线程个数和cpu个数相同,但是可以通过参数设置。下面就列举一些常见的Stream操作集合的例子。
目录
前提条件:
一、forEach()
二、map()函数
三、Collectors.grouping()函数的使用
四、filter()函数
前提条件:
测试用Person类:
public class Person
{
private String name;
private Integer age;
private String gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
测试用Man类,该类是Person类子类,拥有自己特别的属性target。
public class Man extends Person {
private String target;
public String getTarget() {
return target;
}
public void setTarget(String target) {
this.target = target;
}
}
Main函数代码:
List<Person> persons = new LinkedList();
Person person1 = new Person();
Person person2 = new Person();
Person person3 = new Person();
Person person4 = new Person();
person1.setName("张三");
person1.setAge(24);
person1.setGender("男");
person2.setName("李四");
person2.setAge(44);
person2.setGender("男");
person3.setName("王五");
person3.setAge(34);
person3.setGender("女");
person4.setName("小二");
person4.setAge(14);
person4.setGender("男");
persons.add(person1);
persons.add(person2);
persons.add(person3);
persons.add(person4);
一、forEach()
该函数和for循环相同,主要作用就是遍历集合里面的所有元素,没有返回值。
persons.parallelStream().forEach(person -> System.out.println(person.getName() + "--" + person.getAge() + "--" + person.getGender()));
运行结果:
二、map()
该函数用于转换集合里面的元素,比如,将Person类里名字提取出来组成一个List<String>类型,这个时候就做了一个转换:List<Person>→List<String>,代码如下:
List<String> personNames = persons.parallelStream().map(person -> person.getName()).collect(Collectors.toList());
personNames.parallelStream().forEach(System.out::println);
运行结果:
map()函数里面的lambda表达式需要有一个返回值,返回值的类型就是你最后想要转换成的类型。如果你想转换成Integer的List,那么你就只需要返回person.getAge()。
当lambda表示足够简单,就不需要写return关键字来返回自己需要的类型,如果逻辑比较复杂,需要2条以上的语句才能返回想要的结果,那么就需要写return语句,比如,现在我把person类集合转换为其子类man类的集合:
List<Man> mans = persons.parallelStream().map(person -> {
Man oneMan = new Man();
oneMan.setName(person.getName());
oneMan.setTarget("我是子类Man,我的名字是" + person.getName());
return oneMan;
}).collect(Collectors.toList());
mans.parallelStream().forEach(man -> System.out.println(man.getName() + "--" + man.getTarget()));
运行结果:
另外说一句,Collectors类可以转换如下集中集合:List、Set、Map,不仅仅只有toList()方法,其中还有很多其他方法,比如分组groupingBy,统计counting等,非常实用,下面就举一个通过grouping函数,将list转换为map的例子。
三、Collectors.groupingBy()
现在将persons集合转换成,以person名字为键,person类的集合为值的map<String,List<Person>>,代码如下:
Map<String, List<Person>> nameToPersons = persons.parallelStream().collect(Collectors.groupingBy(Person::getName));
for (Map.Entry<String, List<Person>> nameToPerson : nameToPersons.entrySet()) {
System.out.println("键:" + nameToPerson.getKey() + "--值:" + nameToPerson.getValue().get(0).getName() + "--" + nameToPerson.getValue().get(0).getAge());
}
运行结果:
这里解释一下为什么值是List类型,因为该方法不能确定你的键是否唯一,对应的,有另外的方法应对键唯一的情况,下面我用person的名字和年龄作为键,person作为值。(用什么作为键,和值都是随意改变的)
Map<String, Person> nameToPersons = persons.parallelStream().collect(Collectors.toMap(person -> person.getName() + person.getAge(), person -> person));
for (Map.Entry<String, Person> nameToPerson : nameToPersons.entrySet()) {
System.out.println("键:" + nameToPerson.getKey() + "--值:" + nameToPerson.getValue().getName() + "--" + nameToPerson.getValue().getAge());
}
运行结果:
四、filter()
该函数用作过滤,过滤掉集合中不满足条件的值,保留需要的值。该函数接收一个boolean类型的表达式,如果集合中的值使这个表达式为true,那么就保留,否则移出,当然,如果你没用使用集合中的值参与表达式,那么这个集合最终保留的值取决于表达式。现在我过滤掉persons里面年龄小于40的值,最后结果应该只会留下李四,44岁这个值,代码如下:
List<Person> ageGt40s = persons.parallelStream().filter(person -> person.getAge() > 40).collect(Collectors.toList());
ageGt40s.forEach(person -> System.out.println(person.getName() + "--" + person.getAge() + "--" + person.getGender()));
运行结果如下:
最后再说一下,关于使用parallelStream操作集合,必须考虑多线程的影响,因为其实质是使用多线程同时操作集合的,如果在操作中,对外部变量进行了修改操作,那么需要考虑是否线程安全问题。这里贴上全部main函数测试代码:
public class TestUnitl
{
public static void main(String[] args)
{
List<Person> persons = new LinkedList();
Person person1 = new Person();
Person person2 = new Person();
Person person3 = new Person();
Person person4 = new Person();
person1.setName("张三");
person1.setAge(24);
person1.setGender("男");
person2.setName("李四");
person2.setAge(44);
person2.setGender("男");
person3.setName("王五");
person3.setAge(34);
person3.setGender("女");
person4.setName("小二");
person4.setAge(14);
person4.setGender("男");
persons.add(person1);
persons.add(person2);
persons.add(person3);
persons.add(person4);
//persons.parallelStream().forEach(person -> System.out.println(person.getName() + "--" + person.getAge() + "--" + person.getGender()));
//List<String> personNames = persons.parallelStream().map(person -> person.getName()).collect(Collectors.toList());
//personNames.parallelStream().forEach(System.out::println);
//List<Man> mans = persons.parallelStream().map(person -> {
// Man oneMan = new Man();
// oneMan.setName(person.getName());
// oneMan.setTarget("我是子类Man,我的名字是" + person.getName());
// return oneMan;
//}).collect(Collectors.toList());
//mans.parallelStream().forEach(man -> System.out.println(man.getName() + "--" + man.getTarget()));
//Map<String, List<Person>> nameToPersons = persons.parallelStream().collect(Collectors.groupingBy(Person::getName));
//
//for (Map.Entry<String, List<Person>> nameToPerson : nameToPersons.entrySet()) {
// System.out.println("键:" + nameToPerson.getKey() + "--值:" + nameToPerson.getValue().get(0).getName() + "--" + nameToPerson.getValue().get(0).getAge());
//}
//Map<String, Person> nameToPersons = persons.parallelStream().collect(Collectors.toMap(person -> person.getName() + person.getAge(), person -> person));
//
//for (Map.Entry<String, Person> nameToPerson : nameToPersons.entrySet()) {
// System.out.println("键:" + nameToPerson.getKey() + "--值:" + nameToPerson.getValue().getName() + "--" + nameToPerson.getValue().getAge());
//}
List<Person> ageGt40s = persons.parallelStream().filter(person -> person.getAge() > 40).collect(Collectors.toList());
ageGt40s.forEach(person -> System.out.println(person.getName() + "--" + person.getAge() + "--" + person.getGender()));
}
}
目前笔者比较常用的就这四个函数,上面也总结了浅显的使用方式,为了更加深入了解stream api,笔者也会继续学习了解该技术。