问题 如何从我的代码中删除重复


我有两种类似的方法。其中一个打印出来的东西,其中一个可以节省一些东西。如您所见,有很多重复的代码。我该如何重构它并删除这个重复?

public static void printSomething(List<String> list) {
    for (String item : list) {
        if (item.contains("aaa")) {
            System.out.println("aaa" + item);
        }
        if (item.contains("bbb")) {
            System.out.println("bbb" + item);
        } else {
            System.out.println(item);
        }
    }
}

public static Map<String, String> getSomething(List<String> list) {
    Map<String, String> map = new HashMap<String, String>();
    for (String item : list) {
        if (item.contains("aaa")) {
            map.put("aaa", item);
        }
        if (item.contains("bbb")) {
            map.put("bbb", item);
        } else {
            //do nothing
        }
    }
    return map;
}

更新:

当方法不完全相似时,代码已更新以解决问题


5180
2018-04-23 13:51


起源

这取决于......为什么你有这两种方法...你能分享调用方法吗? - Frank
你可以使用返回值 getSomething() 打印出来的 printSomething();我会这样做,以避免方法返回任何东西(不是设置者的c)。 - adrianp
@HighPerformanceMark抱歉错误。我的意思是重复 - hudi
该编辑从根本上改变了问题,现在你不能再使用第二种方法来实现第一种方法了。 - Keppil
@hudl:问题在于您通过进行此更改使您之前问题的答案无效。你最好先问一个新问题。 - Keppil


答案:


具有方法操作(T t)的通用接口操作可以减少代码。

public interface Action<E> {
        void action(E e);
}

例:

public static void forEach(List<String> list, Action <String> action) {
    for(String s : list){
           action.action(s);

}

现在您只需要2个不同的Action实现。

如果您不想创建类,可以使用匿名类型。

如果你知道c#,这与lambdas类似。

编辑:

使用匿名类型:

public static Map<String, String> getSomething(List<String> list) {
    final Map<String, String> map = new HashMap<String, String>();
    forEach(list, new Action<String>() {
        @Override
        public void action(String e) {
            if (e.contains("aaa")) {
                map.put("aaa", e);
            }
            if (e.contains("bbb")) {
                map.put("bbb", e);
            } else {
                // do nothing
            }
        }
    });
    return map;
}

创建课程:

public static Map<String, String> getSomething2(List<String> list) {
    final Map<String, String> map = new HashMap<String, String>();
    forEach(list, new ListToMapAction(map));
    return map;
}


public class ListToMapAction implements Action<String> {

    Map<String, String> map;

    public ListToMapAction(Map<String, String> map) {
        this.map = map;
    }

    @Override
    public void action(String e) {
        if (e.contains("aaa")) {
            map.put("aaa", e);
        }
        if (e.contains("bbb")) {
            map.put("bbb", e);
        } else {
            // do nothing
        }
    }

}

3
2018-04-23 14:02



抱歉,但我不明白你的例子。你的方法什么都没有返回,所以我该如何获取我的地图 - hudi
编辑完全实施 - Tiago Almeida
什么时候你打印一些东西?我认为方法行动仍然会有一些重复 - hudi
是的,它会重复:\列表中的“aaa”和“bbb”元素是什么?如果是,您可以比较两个列表,代码会更短。 - Tiago Almeida


假设其中的顺序 println 的 "aaa" 和 "bbb" 出现没关系,你可以替换执行 printSomething 同

public static void printSomething(List<String> list) {
  Map<String, String> map = getSomething(list);
  for(Map.Entry<String, String> entry : map) {
    System.out.println(entry.getKey() + entry.getValue());
  }
}

7
2018-04-23 13:57



+1。这是假设打印输出的顺序无关紧要。 - Keppil
对 - 我打算写一下,感谢你指出来。 - tehlexx
hm thx这将有效,如果方法将是相同但如果打印将包含:... else {System.out.println(“bbb”+ item); }并获得...其他{// doNothing} - hudi
这个解决方案错过了案例 item 不包含“aaa”或“bbb”; printSomething 处理这种情况,但是 getSomething 放下它(也许在编辑问题时它会改变)。 - kuporific


在具有第一类函数的编程语言中,您将传递一个函数作为参数,指示您想在循环内执行的操作(例如,请参阅下面的更新)。 Java将在版本8中使用lambdas,但它们并不完全符合要求。

在当前的Java状态中,你必须解决一些问题 - 例如,将额外的参数传递给方法;或者你可以传递实现接口的匿名内部类,但恕我直言,甚至比我建议的更丑:

static void printSomething(List<String> list, boolean print)

如果 print 是 true 然后在循环内打印,否则添加到 Map。当然,你必须添加几个 if在循环内部检查这种情况,并在开始时,一个额外的 if 确定是否 Map 是要初始化。无论哪种方式,该方法返回一个 Map,但是 Map 可 null 用于印刷案例。这就是我的意思:

static Map<String, String> processSomething(List<String> list, boolean print) {

    Map<String, String> map = null;
    if (!print)
        map = new HashMap<String, String>();

    for (String item : list) {
        if (item.contains("aaa")) {
            if (print)
                System.out.println("aaa" + item);
            else
                map.put("aaa", item);
        }
        if (item.contains("bbb")) {
            if (print)
                System.out.println("bbb" + item);
            else
                map.put("bbb", item);
        } else if (print) {
            System.out.println(item);
        }
    }

    return map;

}

UPDATE

例如,在Python中 - 它允许将函数作为参数传递,这就是你如何以优雅的方式解决问题:

def processSomething(lst, func):
    result = None
    for item in lst:
        if 'aaa' in item:
            result = func(item, 'aaa', result)
        elif 'bbb' in item:
            result = func(item, 'bbb', result)
        else:
            result = func(item, '', result)
    return result

def printer(item, key, result):
    print key + item

def mapper(item, key, result):
    if not result:
        result = {}
    if key:
        result[key] = item
    return result

看看它怎么运作:

processSomething(['aaa', 'bbb', 'ccc'], printer)
=> aaaaaa
   bbbbbb
   ccc

processSomething(['aaa', 'bbb', 'ccc'], mapper)
=> {'aaa': 'aaa', 'bbb': 'bbb'}

2
2018-04-23 13:55



这是一个非常丑陋的例子。这个方法的名字是打印还是得到?第二,你仍然有空,所以你什么也没有 - hudi
这个名字可能是通用的。并且该方法必须始终返回Map,即使它是null - Óscar López
好建议。而且你总是可以传递一个接口的实现 - 委托模式。 - Jasper Blues
你的例子肯定会奏效,但你必须承认这不是一个很好的例子 - hudi
hm函数作为参数:)非常好。 - hudi