• 让数据流转换代码更加健壮流畅:List的Stream包装


    为什么业务代码总是显得不够清晰 ? 因为开发人员总喜欢把业务与技术细节掺杂在一起。如下所示:

    要改善这样的代码,需要将技术细节提取成可复用的基础库,而业务则可写成声明式的:

    先创建一个 StreamUtil 工具类:

    
    public class StreamUtil {
      public static <T,R> List<R> map(List<T> data, Function<T, R> mapFunc) {
        if (CollectionUtil.isEmpty(data)) { return new ArrayList();  }
        return data.stream().map(mapFunc).collect(Collectors.toList());
      }
    
    
      public static <T> List<T> filter(List<T> data, Predicate<T> filterFunc) {
        if (CollectionUtil.isEmpty(data)) { return new ArrayList();  }
        return data.stream().filter(filterFunc).collect(Collectors.toList());
      }
    
    
      public static <T,R> List<R> filterAndMap(List<T> data, Predicate<T> filterFunc, Function<T, R> mapFunc) {
        if (CollectionUtil.isEmpty(data)) { return new ArrayList();  }
        return data.stream().filter(filterFunc).map(mapFunc).collect(Collectors.toList());
      }
    }
    
    

    则原来 stream 流转换代码可写成:

    
    rules = StreamUtil.filter(rules, rule -> BaselineUtils.matchPlatform(rule, platforms));
    baseLineRules = StreamUtil.filter(rules, rule -> rule.getFamily() == BaselineRule.FAMILY_SYSTEM);
    
    

    实际上, StreamUtil.filter 不如 rules.filter(testFunc) 更可读和流畅。如果能写成如下更好:

    
    stream(rules).filter(rule -> BaselineUtils.matchPlatform(rule, platforms)); 
    
    

    这需要对 List 做一个 Stream 的包装:

    ListStream.java

    
    /**
     * @Description 列表的 Stream 包装
     * @Date 2021/5/16 7:51 上午
     * @Created by qinshu
     */
    public class ListStream<T> {
    
        private List<T> origin;
    
        public ListStream(List<T> list) {
            if (list == null) {
                this.origin = new ArrayList<>();
            }
            else {
                this.origin = list;
            }
        }
    
        public static <T> ListStream<T> stream(List<T> list) {
            return new ListStream<>(list);
        }
    
        public  <R> List<R> map(Function<? super T, R> func) {
            return origin.stream().map(func).collect(Collectors.toList());
        }
    
        public  <R> Set<R> mapToSet(Function<? super T, R> func) {
            return origin.stream().map(func).collect(Collectors.toSet());
        }
    
        public  List<T> filter(Predicate<? super T> predicate) {
            return origin.stream().filter(predicate).collect(Collectors.toList());
        }
    
        public <R> List<R> filterAndMapChain(List<Predicate<? super T>> beforeFilters,
                                                      Function<? super T,R> mapFunc, Predicate<R>... afterFilters) {
            Stream<T> stream = origin.stream();
            Stream<R> midResult = null;
            if (beforeFilters != null) {
                for (Predicate f: beforeFilters) {
                    stream = stream.filter(f);
                }
            }
            if (mapFunc != null) {
                midResult = stream.map(mapFunc);
            }
            if (afterFilters != null) {
                for (Predicate<R> f: afterFilters) {
                    midResult = midResult.filter(f);
                }
            }
            return midResult.collect(Collectors.toList());
        }
    
    
    }
    
    
    

    单测:

    
    public class ListStreamTest {
    
        @Test
        public void testNull() {
            List<Integer> ints = stream(null).map(x -> (int)x + 1);
            Assert.assertEquals(ints.size(), 0);
        }
    
        @Test
        public void testMap() {
            List<Integer> ints = stream(Arrays.asList(1,2,3,4,5)).map(x -> x*2);
            Assert.assertArrayEquals(ints.toArray(new Integer[0]), new Integer[]{2,4,6,8,10});
        }
    
        @Test
        public void testFilter() {
            List<Integer> ints = stream(Arrays.asList(1,2,3,4,5)).filter(x -> x%2 ==0);
            Assert.assertArrayEquals(ints.toArray(new Integer[0]), new Integer[]{2,4});
        }
    
        @Test
        public void testFilterAndMapChain() {
            List<Integer> ints = stream(Arrays.asList(1,2,3,4,5)).filterAndMapChain(
                    Arrays.asList(x -> x%2==1),
                    x -> x*2,
                    x -> x > 8);
            Assert.assertArrayEquals(ints.toArray(new Integer[0]), new Integer[]{10});
        }
    }
    
    

    这样,数据流转换代码就更加健壮和流畅。

    很多人或许会觉得:把代码写得那么好图啥?其实,我是把代码表达当成一种思维的训练。 好代码不仅仅关乎习惯和态度,也关乎对设计和技术的理解。

  • 相关阅读:
    eslient配置
    webpack实战——手写常用plugin
    自己实现一个大文件切片上传+断点续传
    小程序长列表优化实践
    GitKraken 正體中文
    ruby Sequel 连接 PostgreSQL
    安装 Window Terminal 并连接wsl的Ubuntu系统
    ruby sinatra+puma+Nginx by Ubuntu
    ruby symbol 用法(:变量)
    win10配置子系统Ubuntu子系统(无需通过Windows应用市场)
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/14773144.html
Copyright © 2020-2023  润新知