• java8函数式编程(2)


    /**
     * @author zhangdi
     * @description  常用的流操作
     */
    public class LambdaChapter3_3 {
        public static void main(String[] args) {
            // new LambdaChapter3_3().testCollect();
            // new LambdaChapter3_3().testMap_usingMap();
            // new LambdaChapter3_3().testfilter_usingLambda();
            // new LambdaChapter3_3().testflatMap();
            new LambdaChapter3_3().testMaxAndMin();
    
        }
    // 3.3.1 collect(toList()) :collect(toList()) 方法由 Stream 里的值生成一个列表,
        // 是一个及早求值操作。
        public void testCollect() {
            List<String> collected = Stream.of("a", "b", "c") // <1>
                    .collect(Collectors.toList()); // <2>
            assertEquals(Arrays.asList("a", "b", "c"), collected); // <3>
    
        }
    
        // 3.3.2 map 如果有一个函数可以将一种类型的值转换成另外一种类型, map 操作就可以使用该函数, 将一个流中的值转换成一个新的流
        /**
         * 使用 for 循环将字符串转换为大写
         */
        public void testMap_usingFor() {
            List<String> collected = new ArrayList<>();
            for (String string : asList("a", "b", "hello")) {
                String upperCase = string.toUpperCase();
                collected.add(upperCase);
            }
            assertEquals(asList("A", "B", "HELLO"), collected);
        }
    
        /**
         * 使用 map 循环将字符串转换为大写
         */
        public void testMap_usingMap() {
            List<String> collected = Stream.of("a", "b", "hello").map(string -> string.toUpperCase())
                    .collect(Collectors.toList());
        }
    
        // 3.3.3 filter ;遍历数据并检查其中的元素时, 可尝试使用 Stream 中提供的新方法 filter
        /**
         * 使用循环遍历列表, 使用条件语句做判断
         */
        public void testfilter_usingFor() {
            List<String> beginningWithNumbers = new ArrayList<>();
            for (String value : asList("Demacia", "Bilgewater", "2Valoran")) {
                if (isDigit(value.charAt(0))) {
                    beginningWithNumbers.add(value);
                }
            }
            assertEquals(asList("2Valoran"), beginningWithNumbers);
        }
    
        /**
         * 函数式风格
         */
        public void testfilter_usingLambda() {
            List<String> beginningWithNumbers = Stream.of("Demacia", "Bilgewater", "2Valoran")
                    .filter((value) -> isDigit(value.charAt(0))).collect(toList());
            assertEquals(asList("2Valoran"), beginningWithNumbers);
        }
    
        // 3.3.4 flatMap: flatMap 方法可用 Stream 替换值, 然后将多个 Stream 连接成一个 Stream
        // 前面已介绍过 map 操作, 它可用一个新的值代替 Stream 中的值。 但有时, 用户希望让 map
        // 操作有点变化, 生成一个新的 Stream 对象取而代之。
        /**
         * Question:假设有一个包含多个列表的流, 现在希望得到所有数字的序列。
         * 包含多个列表的 Stream
         */
        public void testflatMap() {
            List<Integer> together = Stream.of(asList(1, 2), asList(3, 6)).flatMap(value -> value.stream())
                    .collect(toList());
            assertEquals(asList(1, 2, 3, 6), together);
        }
    
        // 3.3.5 max和min:Stream 上常用的操作之一是求最大值和最小值
        /**
         * 使用 Stream 查找最短曲目
         */
        public void testMaxAndMin() {
            List<Track> tracks = asList(new Track("Bakai", 524), new Track("Violets for Your Furs", 378),
                    new Track("Time Was", 451));
            Track shortestTrack = tracks.stream().min(Comparator.comparing(track -> track.getLength())).get();
    
            /**这种new Track("Violets for Your Furs", 378)的方式会报错:Exception in thread "main" java.lang.AssertionError: 
             expected:<testLambda.LambdaChapter3_3$Track@5b8540fd> but was:<testLambda.LambdaChapter3_3$Track@f6dff17f>
            */
            // assertEquals(new Track("Violets for Your Furs", 378) ,shortestTrack);
            assertEquals(tracks.get(1), shortestTrack);
        }
    
        // 3.3.6 通用模式
        /**
         * 使用 for 循环查找最短曲目
         */
        public void testMaxAndMin_usingFor() {
            List<Track> tracks = asList(new Track("Bakai", 524), new Track("Violets for Your Furs", 378),
                    new Track("Time Was", 451));
            Track shortestTrack = tracks.get(0);// 假定第一个track为最短曲目
            for (Track track : tracks) {
                if (track.getLength() < shortestTrack.getLength()) {
                    shortestTrack = track;
                }
            }
            assertEquals(tracks.get(1), shortestTrack);
    
        }
    
        // 例 3-15 中的伪代码体现了通用模式的特点:reduce 模式 例3-15
        public void forkCode() {
            // Object accumulator = initialValue;
            // for (Object element : collection) {
            // accumulator = combine(accumulator, element);
            // }
        }
    
        // 3.3.7 reduce:reduce 操作可以实现从一组值中生成一个值。 在上述例子中用到的 count、 min 和 max 方法,
        // 因为常用而被纳入标准库中。 事实上, 这些方法都是 reduce 操作。
        /**
         * 使用 reduce(reduce的类型是BinaryOperator) 求和:将两个参数相加, acc 是累加器, 保存着当前的累加结果
         */
        public void testSum_usingReduce() {
            int count = Stream.of(1, 2, 3).reduce(0, (acc, element) -> acc + element);
            assertEquals(6, count);
        }
    
        // 例 3-17 展开 reduce 操作
        public void testReduce_expand_To_Sum() {
            BinaryOperator<Integer> accumulator = (acc, element) -> acc + element;
            int count = accumulator.apply(accumulator.apply(accumulator.apply(0, 1), 2), 3);
        }
    
        // 例 3-18 使用命令式编程方式求和 :在命令式编程方式下, 每一次循环将集合中的元素和累加器相加, 用相加后的结果更新累加器的值。
        public void testLambda_To_Sum() {
            int acc = 0;
            for (Integer element : asList(1, 2, 3)) {
                acc = acc + element;
                String str = "1";
    
            }
            assertEquals(6, acc);
        }
    
        // 3.3.8 整合操作 :如何将问题分解为简单的 Stream 操作
        // 第一个要解决的问题是, 找出某张专辑上所有乐队的国籍。
        /*
         * 问题步骤分解: 1. 找出专辑上的所有表演者。 2. 分辨出哪些表演者是乐队。 3. 找出每个乐队的国籍。 4. 将找出的国籍放入一个集合。
         */
        @Test
        public void findnNationality() {
            // Album album2 = SampleData.manyTrackAlbum;
            Album album = new Album("album_test",
                    new ArrayList<Track>(Arrays.asList(new Track("track", 2), new Track("track2", 3))),
                    new ArrayList<Artist>(Arrays.asList(new Artist("the tester", "china"), new Artist("haha", "USA")))
    
            );
            Set<String> set = album.getMusicians().filter((artist) -> artist.getName().startsWith("the"))// 假设所有乐队都以"the"开头.
                    .map(artist -> artist.getNationality()).collect(Collectors.toSet());
            for (String string : set) {
                System.out.println("set:" + string);
    
            }
            // System.out.println("set:"+set.toArray().toString());
        }
    
        // 3.4 重构遗留代码
        // 例 3-19 遗留代码: 找出长度大于 1 分钟的曲目 (假定选定一组专辑, 找出其中所有长度大于 1 分钟的曲目名称。)
        public Set<String> findLongTracks(List<Album> albums) {
            Set<String> trackNames = new HashSet<>();
            for (Album album : albums) {
                for (Track track : album.getTrackList()) {
                    if (track.getLength() > 60) {
                        String name = track.getName();
                        trackNames.add(name);
                    }
                }
            }
            return trackNames;
        }
    
        // 例 3-20 重构的第一步: 找出长度大于 1 分钟的曲目
        public Set<String> findLongTracks_lambda_step1(List<Album> albums) {
            Set<String> trackNames = new HashSet<>();
            // 使用 Stream 的 forEach 方法替换掉 for 循环
            albums.stream().forEach(album -> {
                album.getTracks().forEach(track -> {
                    if (track.getLength() > 60) {
                        trackNames.add(track.getName());
                    }
                });
            });
            return trackNames;
    
        }
    
        // 例 3-21 重构的第二步
        public Set<String> findLongTracks_lambda_step2(List<Album> albums) {
            Set<String> trackNames = new HashSet<>();
            albums.stream().forEach(album -> {
                // 最内层的 forEach 方法有三个功用: 找出长度大于 1 分钟的曲目, 得到符合条件的曲目名称, 将曲目名称加入集合 Set
                album.getTracks().filter(track -> track.getLength() > 60).map(track -> track.getName())
                        .forEach(name -> trackNames.add(name));
            });
            return trackNames;
        }
    
        // 例 3-22 重构的第三步: 找出长度大于 1 分钟的曲目
        public Set<String> findLongTrackslambda_step3(List<Album> albums) {
            Set<String> trackNames = new HashSet<>();
            // 任何时候想转化或替代代码, 都该使用 map 操作。 这里将使用比 map 更复杂的 flatMap 操作, 把多个
            // Stream 合并成一个 Stream 并返回。
            albums.stream().flatMap(album -> album.getTracks()).filter(track -> track.getLength() > 60)
                    .map(track -> track.getName()).forEach(name -> trackNames.add(name));
            return trackNames;
        }
    
        // 例 3-23 重构的第四步: 找出长度大于 1 分钟的曲目
        public Set<String> findLongTrackslambda_step4(List<Album> albums) {
            return albums.stream()
                    .flatMap(album->album.getTracks())
                    .filter(track->track.getLength()>60)
                    .map(track->track.getName())
                    .collect(Collectors.toSet());
        }
    
    
        //3.6 高阶函数:高阶函数是指接受另外一个函数作为参数, 或返回一个函数的函数。 
    
    
        //  3.8 要点回顾
        //  Ŗ 内部迭代将更多控制权交给了集合类。
        //  Ŗ 和 Iterator 类似, Stream 是一种内部迭代方式。
        //  Ŗ 将 Lambda 表达式和 Stream 上的方法结合起来, 可以完成很多常见的集合操作。
    
    
  • 相关阅读:
    Eclipse中支持js提示
    数据库命名规则
    JavaWeb 命名规则
    Ajax&json
    js中,var 修饰变量名和不修饰的区别
    javaScript知识点
    Bootstrap 栅格系统
    文本框如果不输入任何内容提交过后是一个空字符串还是null
    根据汇总数量依次扣减的SQL新语法
    asp.net中使用forms验证
  • 原文地址:https://www.cnblogs.com/DiZhang/p/12544997.html
Copyright © 2020-2023  润新知