Java1.8新特性之Stream的使用

                                            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,笔者也会继续学习了解该技术。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章