您当前的位置:首页 > 计算机 > 编程开发 > Java

Java8之新特性--Stream详解

时间:02-13来源:作者:点击数:

一、前言

1、Java8中的Stream跟Java.IO中Stream的关系?

两者没有任何关联

Java8中的Stream主要用来对容器/集合数据进行中间操作(filter-筛选,sort-排序,map-类型转换),终止操作(将操作后的数据重新汇总到一个新的容器/集合中)

Java.IO中的Stream主要用来对文件进行读写操作

2、Java8中的Stream可以做什么?

Java8中的Stream主要用来对容器/集合中的数据进行操作,它主要分为三个流程:起始操作,中间操作,终止操作

起始操作:指定一个数据源(一般为集合List,Set等)

中间操作:对数据源(集合)中的数据采用筛选,过滤,类型转换

注:中间操作不会造成对数据源中源数据的污染,即原集合中的数据结构以及数据不会因为Stream的中间操作而改变

终止操作:可以将中间操作后的数据进行分组汇总、统计,并可以针对操作后的数据生成新的容器集合

3、Java8中的Stream语法采用Lambda表达式设计,所以想要了解Java8中的Stream,要有一定的Lambda基础。

关于Lambda的文章,具体可入:https://www.cdsy.xyz/computer/programme/java/230213/cd40528.html

二、Java8中的Stream常用操作演示(主要对工作中常用到的三种中间操作--filter, sort, map进行阐述)

public static void main(String[] args) {
    Long nowTime = System.currentTimeMillis();
    String uid = "1";
    String nickName = "炸鸡小子";
    GenderEnum gender = GenderEnum.男;
    String userName = "zhajixiaozi";
    String password = "123456";
    String address = "上海市虹口区";
    String mobile = "17635696658";
    Timestamp createdOn = new Timestamp(nowTime);

    String uid2 = "2";
    String nickName2 = "炸鸡小子2";
    GenderEnum gender2 = GenderEnum.男;
    String userName2 = "zhajixiaozi2";
    String password2 = "123456";
    String address2 = "上海市虹口区";
    String mobile2 = "17635696658";
    Timestamp createdOn2 = new Timestamp(nowTime);

    String uid3 = "3";
    String nickName3 = "炸鸡小子3";
    GenderEnum gender3 = GenderEnum.男;
    String userName3 = "zhajixiaozi3";
    String password3 = "123456";
    String address3 = "上海市";
    String mobile3 = "17635696658";
    Timestamp createdOn3 = new Timestamp(nowTime);

    Account account1 = new Account(uid, nickName, gender, userName, password, mobile, address, createdOn);
    Account account2 = new Account(uid2, nickName2, gender2, userName2, password2, mobile2, address2, createdOn2);
    Account account3 = new Account(uid3, nickName3, gender3, userName3, password3, mobile3, address3, createdOn3);

    List<Account> bunchOfAccounts = Arrays.asList(new Account[]{account1, account2, account3});
}

1、Stream的中间操作---filter筛选

(1)筛选事例1

// filter 1
List<Account> uidEquals1 = bunchOfAccounts.stream()
        .filter(account -> account != null && "1".equals(account.getUid()))
        .collect(Collectors.toList());

uidEquals1.forEach(account -> System.out.println(account.getNickName()));

该事例是将Account集合中每个account不为NULL并且ID为1的account全部通过中间操作-filter筛选出来,并使用collect进行组合为一个新的集合。

(2)筛选事例2

// filter 2
List<Account> uidEquals2List = bunchOfAccounts.stream()
        .filter(account -> {
            if (account != null) {
                if ("炸鸡小子3".equals(account.getNickName())) {
                    return true;
                }
            }
            return false;
        })
        .collect(Collectors.toList());

uidEquals2List.forEach(account -> System.out.println(account.getNickName()));

该事例主要想告诉大家,如果filter方法体中包含多条语句并结合{}的使用筛选方式,filter方法参数为Predicate函数式接口,它的返回值约定必须为一个boolean类型的值,如何不加{},默认返回方法体中指定的条件表达式的结果。如果遇到业务较复杂的代码,就要使用到return关键字手动返回结果。

2、Stream的中间操作---sort排序

(1)排序事例1--按指定字段升序

// sort 1---默认的升序排序
List<Account> uidSorted1List = bunchOfAccounts.stream()
        .sorted(Comparator.comparing(Account::getUid))
        .collect(Collectors.toList());

uidSorted1List.forEach(account -> System.out.println(account.getUid()));

该事例将id进行默认的升序排序,使用Java8的Stream提供的排序接口,可以不用专门针对对应的实体类实现Comparable接口,并重写compareTo方法。细心的人可能会发现代码中有Account : : getUid,这样一句代码,它就是Java8中的(方法引用),主要配合Lambda以及Stream使用。该排序不仅支持升序,也支持降序,代码如下:

(2)排序事例2--按指定字段降序

// sort 2---降序排序
List<Account> uidSorted2List = bunchOfAccounts.stream()
        .sorted(Comparator.comparing(Account::getUid).reversed())
        .collect(Collectors.toList());
uidSorted2List.forEach(account -> System.out.println(account.getUid()));

降序实现也非常简单,只需要在comparing()方法后再调用reversed方法就可以实现降序排序的功能

(3)该排序还支持中文字母排序,可以按照昵称进行排序,这里博主已经测试通过了,就不贴代码了!

3、Stream的中间操作---map类型转换

(1)类型转换事例1

List<String> account2UidList = bunchOfAccounts.stream()
        .map(account -> account.getUid())
        .collect(Collectors.toList());

account2UidList.forEach(System.out::println);

该事例将原集合中的每一个Account类型的对象集合转换为了一个String类型的集合,并生成一个新的String类型的集合,该集合中存储的是原来集合中的每一个ID值,接收的List<String>并不是提前定好的,而是通过map中的方法体中返回的数据的类型决定的,返回的是什么类型,结果集合就是什么类型。

(2)关于map的方法还有很多,有兴趣的朋友可以自己下去看看。不管map的方法再多,但是万变不离其宗,它都是为了转换类型使用的。

4、以前我们经常使用数据库进行分页,一般是由于数据量比较大,所以每次去查询的时候进行避免由于数据量大,而且SQL中的业务逻辑比较负责,而造成查询时间太长,降低用户的体验度。Java8也为我们提供了相关分页的API

// page
int pageIndex = 0;
int pageSize = 10;
List<Account> pageOfAccount = bunchOfAccounts.stream()
        .skip(pageIndex * pageSize)
        .limit(pageSize)
        .collect(Collectors.toList());

pageOfAccount.forEach(account -> System.out.println(account.getUid()));

skip方法指定跳过(前)元素的个数,limit方法指定总元素个数。将这两个方法进行结合就达到了分页的效果。而且这种分页的方式已经很多公司中都用到!

5、Java8中还支持数据库中常用的分组统计

比如我们要统计每个年龄段手机号码以 "176" 开头的的人数

sql:select count(*) from account where mobile like '176%' group by age;

下面我们用Java来实现分组统计:

// sql: select count(*) from account where mobile like '176%' group by age;
// group by
Map<Integer, List<Account>> GroupByOfAccountCount = bunchOfAccounts.stream()
        .filter(account -> account != null && account.getMobile().startsWith("176"))
        .collect(Collectors.groupingBy(Account::getAge));

GroupByOfAccountCount.keySet().forEach(key -> System.out.println(GroupByOfAccountCount.get(key).size()));

6、除此之外,Collectors下还有很多相关的方法,统计最大数,最小数,平均数等等。在这里就不给大家一一列举了,有兴趣的朋友下来可以自己练练手!

到这里,Java8的Stream已经接近尾声了,还是希望大家可以对Java8的新特性进行熟悉掌握,对日后的开发以及跳槽有很大的帮助!

本次讲解源代码已放置到GitHub中,有需要的可以去下载,地址:https://github.com/wuyongfei-1/Java8-Stream

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门