使用函数的返回是一个好习惯,其中返回值是作为参数提供的对象吗?

时间:2015-02-10 09:36:26

标签: java performance hashmap theory

我只是想问一下这是一个很好的java练习还是有更好的方式(官方方式)来做同样的事情。

首先,我需要更新一些hashmap信息:

Map<Date, Object> rows = new HashMap<Date, Object>();

这是excel行的对象,对于每个日期(即10月1日,10月2日等)和包含该行信息的对象。

所以,为了获得这些信息,我有一些方法,如:

rows = performQuery1(rows, foo, bar, initDate, endDate);
rows = performQuery2(rows, someDAO, foo);

和...

private HashMap<Date, Object> performQuery1(rows, foo, bar, Date, Date) {
  // Some code that adds or removes elements from the hashmap "rows"
  rows.put(date1, o1);

  //Then return the same object
  return rows;
}

所以我的问题是:这是一个很好的java练习吗?

rows = performQuery1(rows, foo, bar, initDate, endDate);
rows = performQuery2(rows, someDAO, foo);
是不是?

2 个答案:

答案 0 :(得分:4)

问题确实非常广泛,或者集中在“最佳实践”部分,可能基于意见 - 但不是主要基于意见,因为对于这样的模式存在有效的论据。

通常你有一个方法可以在某个地方获取数据,并且应该把它放到目标数据结构中(可能是一个集合,或者你的情况下的一个地图)。

这种方法的签名有几种选择(大致在你的例子中,但这种模式可以推广)。

第一个可能是

/**
 * Computes ... something, and returns the result as a map
 */
Map<Date, Result> execute(Date d0, Date d1) { ... }

第二个可能是

/**
 * Computes ... something, and places the results into the
 * given map
 */
void execute(Date d0, Date d1, Map<Date, Result> results)  { ... }

但是,为了获得最大的灵活性,我经常会参考第三个选项(这是您实际询问的那个):

/**
 * Computes ... something, and places the results into the
 * given map, which is then returned. If the given map is
 * null, then a new map will be created and returned.
 */
Map<Date, Result> execute(
    Date d0, Date d1, Map<Date, Result> results)  { ... }

这有几个好处:

  • 您可以方便地让通话创建新地图:

    Map<Date, Result> results = execute(d0, d1, null);
    
  • 您可以确定目标数据结构的实现。如果您总是返回新地图,则无法在HashMapLinkedHashMap之间进行选择。将目标数据结构传递给方法允许您调用

    Map<Date, Result> results = 
        execute(d0, d1, new HashMap<Date, Result>());
    

    Map<Date, Result> results = 
        execute(d0, d1, new LinkedHashMap<Date, Result>());
    
    分别

  • 您不必为每次通话创建新地图。例如,您可以创建一系列调用

    Map<Date, Result> results = new HashMap<Date, Result>();
    execute(d0, d1, results);
    execute(d2, d3, results);
    

    在给定地图中累积结果


考虑到这种方法可以简单地模拟这两种方法,这种方法的力量可能变得更加明显:

class DB {

    // The private method that can emulate both public methods:
    private Map<Date, Result> executeImpl(
        Date d0, Date d1, Map<Date, Result> results);

    // The implementation that returns a new map
    public Map<Date, Result> execute(Date d0, Date d1) {
        return executeImpl(d0, d1, null);
    }

    // The implementation that fills a given map
    public void execute(Date d0, Date d1, Map<Date, Result> results) {
        executeImpl(d0, d1, results);
    }

}

旁白:在Java SDK的某些地方也使用了类似的模式。例如,在不同的应用案例中:BufferedImageOp#filter

  

BufferedImage filter(BufferedImage src, BufferedImage dest)

     

...如果目标图像为null,则创建具有适当ColorModel的BufferedImage。

     

返回:已过滤的BufferedImage

答案 1 :(得分:1)

问题的核心归结为Is Java "pass-by-reference" or "pass-by-value"?

此外,您应该返回新创建的对象或修改参数引用的对象,但不能同时修改两者。有一些有用的例外 比如Method chaining,但这似乎并非如此。

当您从方法返回数据时,程序员将期望数据是新创建的对象,而通过参数引用的对象保持不变。让方法返回void(或成功代码)提示程序员该方法修改了参数引用的对象,而不是返回一个新对象并使代码更容易阅读。