Java流操作总结

Java流(Stream)操作自Java 8引入,通过Stream操作可以简化代码编写,提高代码执行效率。流整体操作分为创建(Supplier)、转换、约简和收集几个操作。

创建流

创建流最常见的方式是调用Collection.stream()方法,将集合数据转换为流,也可以通过generate方法创建流。如下所示:

    public static void main(String[] args) {
        //从Collection中产生流
        ArrayList<String> strings = new ArrayList<>();
        for (int i = 0; i < 20; ++i) {
            strings.add("string" + i);
        }

        Stream<String> stringStream = strings.stream();
        show("stringStream", stringStream);

        //使用generate产生流
        Stream<Integer> integerStream = Stream.generate(() -> (int) (Math.random() * 100));
        show("integerStream", integerStream);
        //使用iterate产生序列
        Stream<Integer> integerStream1 = Stream.iterate(0, n -> n + 1);
        show("integerStream1", integerStream1);

        //使用of方法创建流
        Stream<String> stringStream1 = Stream.of("Bob", "Mark", "Alice", "Edd");
        show("stringStream1", stringStream1);

        //正则表达式产生流
        String sentences = "I had a dog whose name was Bingo. B, I, N, G, O, Bingo was his name, Oh!";
        Stream<String> words = Pattern.compile("\\PL+").splitAsStream(sentences);
        show("PatterStream", words);
    }

    public static<T> void show(String title, Stream<T> stream) {
        final int size = 10;
        List<T> array = stream.limit(size).collect(Collectors.toList());
        System.out.println(title + ": ");
        for (int i = 0; i < array.size(); ++i) {
            if (i > 0) {
                System.out.print(", ");
            }
            if (i < array.size()) {
                System.out.print(array.get(i));
            } else {
                System.out.print("...");
            }
        }
        System.out.println();
    }   

流的转换

流的转换即将一个给定的流通过流的方法转换为另一个流,常见的方法有filter,map,distinct, sorted,reverse等方法。

  • filter方法保留满足filter方法中的条件表达式的元素;
  • map方法可以对流中的元素进行一个转换操作;
  • distinct方法将流中重复的元素去除
  • sorted按给定的比较方法进行排序
String sentences = "I had a dog whose name was Bingo. B, I, N, G, O, Bingo was his name, Oh!";
//保留长度大于2的单词
Stream<String> words1 = Pattern.compile("\\PL+").splitAsStream(sentences).filter(s -> s.length() > 2);
show("PatterStream1", words1);

//将单词转换为大写
Stream<String> words2 = Pattern.compile("\\PL+").splitAsStream(sentences).map(String::toUpperCase);
show("PatterStream2", words2);

//去除重复的单词
Stream<String> words3 = Pattern.compile("\\PL+").splitAsStream(sentences).distinct();
show("PatterStream3", words3);

//按长度对单词进行排序
Stream<String> words4 = Pattern.compile("\\PL+").splitAsStream(sentences).sorted(Comparator.comparing(String::length));
show("PatterStream4", words4);

 //按长度对单词进行排序后反序
 Stream<String> words5 = Pattern.compile("\\PL+").splitAsStream(sentences).sorted(Comparator.comparing(String::length).reversed());
 show("PatterStream4", words5);

流的约减(Reduce)

流经过处理后,提供了一系列方法从流中抽取数据。抽取数据是一种终结操作,常用的方法如下:

  • count方法:获取流中满足条件的元素个数
  • min、max方法:按照给定的比较方法获取最小最大值,注意该方法返回的是一个Optional<T>的包装类,这是因为流可能为空。
  • find查找方法:包括findFirst,findAny等。
  • match方法:根据条件查找是否有匹配条件的元素,有anyMatch,allMatch和noneMatch,返回的是boolean类型。
  • 消费流:通过方法消费流中的元素,例如使用forEach迭代,传递方法处理流中的每个元素。
  • 转换为Collection或数组:通过collect方法传递Collectors类提供的toCollection方法可以转换为Collection或者调用toArray方法转换为数组。
  • 拼接:使用Collectors.join方法可以拼接流.
  • 统计,使用IntSummaryStatistics、DoubleSummaryStatistics和LongSummaryStatistics方法构造统计对象,获取 总数,平均值,最大值,最小值。需要注意调用Collectors.summarizing{Int,Double, Long}方法需要传递一个lambda表达式,确定统计的内容。
//获取单词的数量
long wordsCount = Pattern.compile("\\PL+").splitAsStream(sentences).filter(s -> s.length() > 2).count();
System.out.println("Number of words length greater than 2: " + wordsCount);

//获取最长的单词
Optional<String> longestWord = Pattern.compile("\\PL+").splitAsStream(sentences).max(Comparator.comparing(String::length));
System.out.println("longestWord: " + longestWord.orElse("null"));

//获取最短的单词
Optional<String> shortestWord = Pattern.compile("\\PL+").splitAsStream(sentences).min(Comparator.comparing(String::length));
System.out.println("shortestWord: " + shortestWord.orElse("null"));

//获取第一个以h开头的单词
Optional<String> firstWordsStartWithH = Pattern.compile("\\PL+").splitAsStream(sentences)
                .filter(s -> s.toLowerCase().startsWith("h")).findFirst();
System.out.println("firstWordsStartWithH: " + firstWordsStartWithH.orElse("Not Found"));

//获取任何一个以h开头的单词
Optional<String> anyWordsStartWithH = Pattern.compile("\\PL+").splitAsStream(sentences)
                .filter(s -> s.toLowerCase().startsWith("h")).findAny();
System.out.println("anyWordsStartWithH: " + anyWordsStartWithH.orElse("Not Found"));

//查找其中是否有was这个单词
boolean hasWas = Pattern.compile("\\PL+").splitAsStream(sentences).anyMatch("was"::equals);
System.out.println("hasWas: " + hasWas);

//查找其中全部是was这个单词
boolean allWas = Pattern.compile("\\PL+").splitAsStream(sentences).allMatch("was"::equals);
System.out.println("allWas: " + allWas);

//使用forEach方法打印全部单词的大写
Pattern.compile("\\PL+").splitAsStream(sentences).map(String::toUpperCase).forEach(System.out::print);

//将流转为Collection
List<String> wordsList = Pattern.compile("\\PL+").splitAsStream(sentences).collect(Collectors.toList());
System.out.println("wordsList: " + wordsList);

//将流转为数组
String[] wordsArray = Pattern.compile("\\PL+").splitAsStream(sentences).toArray(String[]::new);
System.out.println("wordsArray: " + Arrays.toString(wordsArray));

//将流拼接为字符串
String wordsToSentences = Pattern.compile("\\PL+").splitAsStream(sentences).collect(Collectors.joining(", "));
System.out.println("wordsToSentences: " + wordsToSentences);

//数据统计:统计单词的长度
IntSummaryStatistics lengthSummary = Pattern.compile("\\PL+").splitAsStream(sentences).
                collect(Collectors.summarizingInt(String::length));
System.out.println("Longest word length: " + lengthSummary.getMax());
System.out.println("Shortest word length: " + lengthSummary.getMin());
System.out.println("Average word length: " + lengthSummary.getAverage());
  • 收集到Map:使用Collectors.toMap转到Map数据中。
  • 分组:使用groupingBy进行分组
    public static class User {
        private String name;
        private int id;
        //1=male, 0 = female, 2= unknown
        private int sex = 2;

        public User(int id, String name, int sex) {
            this.id = id;
            this.name = name;
            if (sex == 0 || sex == 1) {
                this.sex = sex;
            }
        }

        public int getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        public int getSex() {
            return sex;
        }

        @Override
        public String toString() {
            return "User{id = " + id + ", name = " + name + ", sex = " + sex + "}";
        }
    }

    //省略部分代码...

    public static Stream<User> userStream() {
        return Stream.of(
                new User(1, "Box", 1),
                new User(2, "Succi", 0),
                new User(3, "Lily", 0),
                new User(4, "Sara", 0),
                new User(5, "Mark", 1)
        );
    }
    

    //main方法
    public static void main(String[] args) {
        //...
        //映射为id -> User格式
        Map<Integer, User> userMap = userStream().collect(Collectors.toMap(User::getId, Function.identity()));
        for (Integer key:userMap.keySet()) {
            System.out.println("id " + key + ": " + userMap.get(key));
        }
        
        //映射为id -> User.name格式
        Map<Integer, String> idToNameMap = userStream().collect(Collectors.toMap(User::getId, User::getName));
        System.out.println(idToNameMap);
        
        //按性别分组
        Map<Integer, Set<User>> sexToUserMap = userStream().collect(Collectors.groupingBy(User::getSex, Collectors.toSet()));
        for (Integer key:sexToUserMap.keySet()) {
            Set<User> usersOfSex = sexToUserMap.get(key);
            System.out.println("Sex " + key + ": " + usersOfSex);
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353