Java8 stream 学习笔记

什么是stream

stream是Java8 中的一个新特性,它主要能让开发人员用函数式编程的方式(如Lamba表达式)对集合做聚合操作。所谓的聚合操作就是对集合的查找、遍历、过滤以及常见计算等。

下面是stream的一些常见操作介绍:

foreach:循环操作
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
map:将每一个元素映射到相应的结果里
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
//get list of unique squares
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter:过滤某些元素
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
//get list of unique squares
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
limit:限制输出流的个数
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
sorted:对输出流元素进行排序
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
Collectors:用于聚合输出流的结果,可拼成list或者string
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

System.out.println("Filtered List: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("Merged String: " + mergedString);

首先,我们创建一个存储了用户信息的列表进行示例,我们先看看如何过滤:

过滤出姓名为xiao ming的用户
User user1 = new User("xiao ming",  12, "小学");
User user2 = new User("mei mei", 18, "大学");
User user3 = new User("li lei", 11, "小学");
User user4 = new User("xiao hong",  15, "初中");

List<User> userList = new ArrayList<>(3);
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);

useList.stream().filter(user -> user.getName().equals("xiao ming")).forEach(user -> System.out.println(user.getGrade()));

你可以看到只要在列表后加上.stream(),默认就会生成一个流。
有了这个流后,你可以调用filter(),并在里边设置过滤条件即可过滤出相应的元素

下面我们再看看基于stream转成其他数据结构,现在我们将这个User类转成另外一个类。
原User类
class User{
    String name;
    int age;
    String grade;
}
异构后的类
class UserInfo{
     String name;
     int age;
     String extend;
}

如果按传统写法,我们肯定就要用for循环遍历原userlist,再一个个赋值过去了,现在有了stream就只需这样:

List<UserInfo> userInfoList = userList.stream.map(tmp->{
                 UserInfo = usrInfo = new UserInfo();
                 usrInfo.setName(tmp.getName());
                 usrInfo.setAge(tmp.getAge());
                 if (tmp.getGrade().equals("大学")){
                       usrInfo.setExtend("university");  
                }
                return usrInfo;
         }).collect(Collectors.toList());

再换个玩法,如果希望list转成map,key为用户名,value为整个用户对象,最后遍历打印map里的对象,那用stream要怎么玩呢?

Map<String, User> userMap = userList.stream().collect(Collectors.toMap(User::getName, user -> user));
userMap.forEach((K, V) -> System.out.println("key:" + K + "val:" + V));

好,我们继续加需求,在原User类上,要记录他所借阅过的书籍,那么数据结构将会变成这样:

原User类
class User{
    String name;
    int age;
    String grade;
    Set<String> books;

    public void addBook(String book) {
        if (this.book == null) {
            this.book = new HashSet<>();
        }
        this.book.add(book);
    }
}

我们要将小明,梅梅借的书读取出来

//初始化
User user1 = new User("xiao ming",  12, "小学");
User user2 = new User("mei mei", 18, "大学");

//添加图书
user1.addBook("Java 8 in Action");
user1.addBook("Spring Boot in Action");
user1.addBook("Effective Java (2nd Edition)");

user2.addBook("Learning Python, 5th Edition");
user2.addBook("Effective Java (2nd Edition)");

List<User> userList = new ArrayList<>(3);
userList.add(user1);
userList.add(user2);

List<String> collect = list.stream()
                        .map(x -> x.getBook())      //Stream<Set<String>>
                        .flatMap(x -> x.stream())   //Stream<String>
                        .distinct()
                        .collect(Collectors.toList());

collect.forEach(x -> System.out.println(x));
按照年级对用户进行分组
Map<String, List<User>> userGroup = userList.stream().collect(Collectors.groupingBy(User::getGrade));
判断用户列表中是否有符合指定年龄段的用户

boolean isAllAdult = useList.stream().allMatch(p -> p.getAge() > 10);
boolean isAnyChild = useList.stream().anyMatch(p -> p.getAge() < 12);

引用来源

  1. https://mkyong.com/java8/java-8-flatmap-example/
  2. https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
  3. https://stackoverflow.com/questions/26684562/whats-the-difference-between-map-and-flatmap-methods-in-java-8
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容