Java =返回对象列表/数组与结果对象(与方法参数相同)

时间:2011-06-06 14:36:46

标签: java oop

这似乎是一个奇怪的问题:我正在努力决定在一个非常精细的层面上使用“类型对象”这是一个好的做法和“高效”。

public Object[] doSomething() {
    Object[] resultList = new Object[] {new Foo(), new Bar()};
    return resultList;
}

public Result doSomething() {
    Result result = new Result();
    result.foo = new Foo();
    result.bar = new Bar();
    return result;
}

public class Result{
    Foo foo;
    Bar bar;
}

我的问题具体如下:

  1. 就CPU周期而言(作为相对数字),第二种方法消耗的资源多少。 (比如100%以上)

  2. 关于记忆消耗的相同问题

  3. NB(这两个问题需要更多地了解,而不是过早优化)

    1. 就“良好的设计实践”而言。你认为版本1是绝对的No-Go还是你认为它实际上并不重要...或者你会建议永远不会返回“对象阵列”(((在面向对象的编程语言中)))... < / LI>

      这是一件事,我总是想知道是否应该为所有内容创建专用对象(用于传递值)或者我应该使用通用对象(和常用方法参数......)

      这个问题也适用于

      public doSomething(Query query ) 
      

      public doSomething(Foo foo, Bar bar, Aaaa, a, Bbbbb)
      

      谢谢

      马库斯

3 个答案:

答案 0 :(得分:6)

  

3。)在“良好的设计实践”方面。你认为版本1是绝对的No-Go还是你认为它实际上并不重要...或者你会建议永远不会返回“对象阵列”(((在一个面向对象的编程语言/关于封装......) ))...

版本1 绝对是禁止的。它几乎完全没有类型。调用者必须知道实际类型以及它们在数组中的位置,并进行适当的转换。您丢失了任何有用的编译时类型检查,并且代码本身显着不太清楚。

我永远不会返回Object[],除非它包含的值是用new Object()构建的。

答案 1 :(得分:2)

我不相信定义一个Result类并返回它在运行时消耗比构建Object[]更多的资源。 (当然,存储和加载类定义的成本微乎其微。)你有不同的数据吗?

由于各种原因,返回无类型的对象数组是不好的做法,其中包括:

  1. 很容易出错。
  2. 维护起来比较困难。
  3. 回归“真实”类型也不是免费的。
  4. 关于您的其他查询:

    public doSomething(Query query) 
    

    public doSomething(Foo foo, Bar bar)
    

    这不那么明确。如果将FooBar打包成Query对象在问题域中有意义,那么我肯定会这样做。如果它只是为了最小化参数的数量而打包(也就是说,你的问题域中没有“查询对象”概念),那么我可能不会这样做。如果这是运行时性能的问题,则答案是(一如既往)分析。

答案 2 :(得分:1)

我必须做一个真正了解的实验,但我猜测对象数组不会明显加快。它甚至可能更慢。毕竟,在任何一种情况下,您都必须创建一个对象:数组对象或Result对象。使用Result对象时,您必须在第一次使用它时从磁盘读取类定义,并且类定义必须在内存中浮动,因此会有一些额外的成本。但是使用数组对象时,必须在将数据拉出时进行强制转换,并且JVM必须对数组进行边界检查(如果调用者尝试检索resultList [12]会发生什么?),这也涉及额外的工作。我的猜测是,如果你只做一次或两次,数组会更快(因为类加载时间),但如果你多次这样做,专用对象会更快(因为转换和数组访问时间) )。但我承认我只是在猜测。

在任何情况下,即使阵列确实具有轻微的性能优势,代码的可读性和可维护性的损失几乎肯定是不值得的。

可能发生的绝对最糟糕的事情是,如果您在数组中返回的值属于同一类但具有不同的语义含义。就像假设你这样做:

public Object[] getCustomerData(int customerid)
{
  String customerName=... however you get it ...
  BigDecimal currentDue=...
  BigDecimal pastDue=...
  return new Object[] {customerName, pastDue, currentDue};
}
... meanwhile, back at the ranch ...
Object[] customerData=getCustomerData(customerid);
BigDecimal pastDue=(BigDecimal)customerData[2];
if (pastDue>0)
  sendNastyCollectionLetter();

你看到错误吗?当它应该是#1时,我将条目#2作为pastDue检索。你可以很容易想象,如果程序员在一个没有思想的时刻计算从一个而不是零开始的字段,就会发生这种情况。或者在一个很长的名单中,如果他错误计算并说#14当它真的是#15。因为两者都具有相同的数据类型,所以这将编译并运行得很好。但我们会向未到期的客户发送不合适的催款单。这对客户关系来说非常糟糕。

好吧,也许这是一个糟糕的例子 - 我只是把它从头脑中拉出来 - 因为我们可能会在测试中发现它。但是,如果我们切换的值很少使用,那么没有人会想到为它们包含测试场景。或者它们的影响是微妙的,因此错误可能会通过测试。就此而言,如果您正在进行改变,或者如果测试人员滑倒等等,也许你不会在测试中发现这个。