Heim  >  Fragen und Antworten  >  Hauptteil

关于java语言表达力不足的几个例子及可有好的封装方法

开发业务过程中 明显感觉到java语言表达力的不足 就好像没有桌子的概念 所以每次提到桌子都得通过这么一长串的文字--有光滑平板、由腿或其它支撑物固定起来的家具,用以吃饭、写字、工作或玩牌 --来表达桌子的概念 反正开发过程中我是有点晕

下面是几个比较典型的例子

业务背景

  • 购买某些商品 会给用户发一些优惠券 如2张满100减50优惠券 1张满200减50优惠券等

  • 我提供一个了接口 接收上述券信息

  • 先查询redis判断该券是不是已经存在 如hmget key 100_50 200_50

  • 如果券不存在 先去创建 然后将其放到redis中 如hmset key 100_50 84678bfd7c1011e6a22b4437e6d0648e

  • 最后得到券编码和张数的映射关系 批量发券 batchSendCouponsToUser(userId,couponCodeCountMap);

两个元素集合 找出对应的另一个集合中同一位置为空的元素

        String[] descArray = {"aaa", "bbb", "ccc"};  // 券描述 如 满100减50
        List<String> codeList = newArrayList("111", null, "333"); // 券编码
        // 找出尚不存在code的券
        List<String> nullElementList = newArrayList();
        for (int i = 0; i < codeList.size(); i++) {
            if (codeList.get(i) == null) {
                nullElementList.add(descArray[i]);
            }
        }
        assertThat(nullElementList).containsExactly("bbb");

一个集合与一个Map通过另一个集合来关联 并生成一个新的Map

        String[] descArray = {"aaa", "bbb", "ccc"}; // 券描述
        List<String> codeList = newArrayList("111", "222", "333"); // 券编码
        Map<String,CouponInfo> descCouponInfoMap = ImmutableMap.of("aaa", new CouponInfo("aaa", 1), "bbb", new CouponInfo("bbb", 2), "ccc", new CouponInfo("ccc", 3)); // 券描述 -- 券信息
       
        // 得到券编码与发放张数Map
        Map<String,Integer> codeCountMap = new HashMap<>();
        for (int i = 0; i < codeList.size(); i++) {
            codeCountMap.put(codeList.get(i), descCouponInfoMap.get(descArray[i]).getCount());
        }


        assertThat(codeCountMap).containsExactly(new DefaultMapEntry("111",1),new DefaultMapEntry("222",2),new DefaultMapEntry("333",3));

两个对象list各抽取一个属性 组成一个Map


        List<Foo> fooList = newArrayList(new Foo("aaa"), new Foo("bbb"), new Foo("ccc"));
        List<Bar> barList = newArrayList(new Bar("111"), new Bar("222"), new Bar("333"));
        Map<String,String> descCodeMap = new HashMap<>(); // 券描述 -- 券编码
        // 将两个List各抽取一个属性成Map
        for (int i = 0; i < fooList.size(); i++) {
            descCodeMap.put(fooList.get(i).getDesc(), barList.get(i).getCode());
        }

        assertThat(descCodeMap).contains(new DefaultMapEntry("aaa","111"),new DefaultMapEntry("bbb","222"),new DefaultMapEntry("ccc","333"));

像第一个还好, 可以提供一个通用的工具类如

static <T>List<T> findNullElementList(List<T> srcList, List<T> destList)

后面两个因为涉及到动态的获取属性值 还不好封装 难道使用java就只能这么麻烦吗?

不知道其他语言针对上述场景是不是一样的麻烦?
如 python javascript ruby 等

巴扎黑巴扎黑2763 Tage vor549

Antworte allen(9)Ich werde antworten

  • ringa_lee

    ringa_lee2017-04-18 09:58:58

    不是很懂你第一段话要表达什么意思……

    我理解为:有没有方便的工具可以实现你的需求?

    有的,java最不缺的就是工具类,基本上只要想到需要什么工具,上网搜一下,99%的情况下都能搜出来。

    建议使用java8+google guava,可以任意搭配使用,两者同时使用更佳。

    就你这3个例子所说的情况,逐一解答如下:

    Q:两个元素集合 找出对应的另一个集合中同一位置为空的元素
    A: 首先,建议写个zip方法把descArraycodeList合并成一个对象数组,然后再对该对象数组进行操作。

    public static <U, V> List<Pair<U, V>> zip(List<? extends U> list1, List<? extends V> list2) throws IllegalArgumentException {
        if (list1 == null || list2 == null || list1.size() != list2.size()) {
            throw new IllegalArgumentException("Two list must have the same size");
        }
        List<Pair<U, V>> results = Lists.newArrayListWithCapacity(list1.size());
        for (int i = 0; i < list1.size(); ++i) {
            // Explicit type parameter just because eclipse is not cool
            // noinspection RedundantTypeArguments
            Pair<U, V> pair = Pair.<U, V>of(list1.get(i), list2.get(i));
            results.add(pair);
        }
        return results;
    }

    然后:

    List<Pair<String, String>> empytCodeList = zip(codeList, descList).stream()
        .filter(v -> Objects.isNull(v.getFirst()))// 找出codeList中为空的对象
        .collect(Collectors.toList());

    Q:一个集合与一个Map通过另一个集合来关联 并生成一个新的Map

    A: 同理,先把两个数组zip成对象数组,然后:

    Map<String, Integer> codeCountMap = zip(codeList, descList).stream()
                    .collect(Collectors.toMap(Pair::getFirst, v -> descCouponInfoMap.get(v.getSecond()).getCount()));//这里有个隐患就是map.get(desc)有可能未null,从而引发空指针

    Q:两个对象list各抽取一个属性 组成一个Map

    A: 同理,先把两个数组zip成对象数组,然后:

    Map<String, String> descCodeMap = zip(fooList, barList).stream()
        .collect(Collectors.toMap(v -> v.getFirst().getDesc(), v -> v.getSecond().getCode()));

    其中你所提到的动态获取属性值,在java8之前,你可以通过反射来动态获取属性值,在java8,你可以通过方法引用来获取,这里我以java8为例:

    public static void getFieldVal(Supplier<?> supplier) {
        return supplier.get();
    }

    couponInfo::getCount就是一个supplier,基于这个原理,以前很多只能通过反射才能实现的功能,在java8中可以通过方法引用去实现。

    以上,就算不用java8,也可以借助guava去优雅的实现这些功能。

    参考资料:

    1. http://ifeve.com/google-guava/

    2. http://www.importnew.com/1036...

    3. http://www.importnew.com/1190...

    Antwort
    0
  • 大家讲道理

    大家讲道理2017-04-18 09:58:58

    其实 Java 8 不需要 zip,

    import java.util.*;
    import java.util.stream.*;

    查找对应集合为空的

    List<String> result = IntStream.range(0, descArray.length)
            .filter(i -> codeList.get(i) == null)
            .mapToObj(i -> descArray[i])
            .collect(Collectors.toList());

    关联 Map

    Map<String, Integer> codeCountMap = IntStream.range(0, descArray.length)
            .boxed()
            .collect(Collectors.toMap(
                    i -> codeList.get(i),
                    i -> descCouponInfoMap.get(descArray[i]).getCount()));

    生成 Map

    Map<String, String> descCodeMap = IntStream.range(0, descArray.length)
            .boxed()
            .collect(Collectors.toMap(
                    i -> descArray[i],
                    i -> codeList.get(i)));

    Antwort
    0
  • 大家讲道理

    大家讲道理2017-04-18 09:58:58

    很明显这是你的问题。
    你知道什么是类和对象吗?
    一切都用list map,当然不行。
    你定义一个优惠券类,有code和desc属性
    List<Ticket> ticketList;
    for(Ticket ticket:ticketList){
    if(ticket.getCode()==null){

    System.out.println(ticket.getDesc());

    }
    }

    第二和第三个也不说了。

    Antwort
    0
  • 高洛峰

    高洛峰2017-04-18 09:58:58

    高层设计的不足,不能通过底层来弥补。

    Antwort
    0
  • 阿神

    阿神2017-04-18 09:58:58

    楼主需要加强抽象设计和数据结构设计。
    第1个场景,按位置对应就是一个非常不稳定的设计。应有具体类型

    class Coupon {
       int id; //对应位置,保证不重复,也不会错位。
       String desc;
       String code;
       
       public boolean notUsed() {
           return code == null;
       }
    }
    

    这样在List中找code为空的会比较好找,但更好的是,用一个unusedList保存所有notUsedCoupon.

    第2个场景做为分类统计,guava中有现成的分组方法,构造好分组后,每组的个数也就知道了。

    第3个场景其实各自取一个属性并无必要,实际上完全可以构造一个对象引用到Foo和Bar,分别使用委托给
    这两个对象。

    就像上面有答主提到,这里缺少高层设计。当有a,b,c三个属性,如果分别设计三个List中,那么就会有
    a->b,b->c的查找过程,复杂一点的操作还有a->(b, c)。如果它们在一个对象中,那么,只要a->o(a,b,c)就可
    以完成大部分数据索引工作。

    Antwort
    0
  • 天蓬老师

    天蓬老师2017-04-18 09:58:58

    python 是解释语言,可以运行时动态获取属性

    不是很懂 java,不过应该有数似的反射机制。

    Antwort
    0
  • ringa_lee

    ringa_lee2017-04-18 09:58:58

    java作为一门古老的语言,如果真如你所说表达力不足,何以成为全世界最流行的语言,只是你学得不好而已

    Antwort
    0
  • PHP中文网

    PHP中文网2017-04-18 09:58:58

    不要用数组或者list去分开票和编码,票和编码应该是一对一的关系吧。在建立模型的时候可以建立一个票的类啊,里面有code属性,这样不就很明确了么

    Antwort
    0
  • PHP中文网

    PHP中文网2017-04-18 09:58:58

    java一门啰嗦型语言, 用java写的代码基本上都挺啰嗦的(8之前).
    java单独处理基本操作确实不如pyhton等语言优雅, 不过可以通过工具类以及其它Groovy等进行弥补.

    Antwort
    0
  • StornierenAntwort