繁体   English   中英

使用list参数作为返回值多次调用void方法比返回List的方法更好?

Multiple calls to a void method using list parameter as return value is better than a method that return a List?

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

简而言之,我的问题是:如果一个方法被多次调用,在内存消耗方面是否更好以使其无效并使用List作为参数来返回其值? 如果真的能节省内存,那么代码难以阅读并不是一种糟糕的做法吗?

让我举一个例子来说明一点。 假设我有一辆 ,每辆车都必须属于一个品牌 我有一个方法可以从品牌列表中返回所有汽车,这种方法使用foreach和方法从一个品牌中检索所有汽车。 如下代码:

private List<Car> getCarsByBrands(List<Brand> brands) {
    List<Car> result = new Arraylist<>;
    for(Brand brand : brands) {
        result.add(getCarsBySingleBrand(brand))
    }
    return result;
}

private List<Car> getCarsBySingleBrand(Brand brand) {
    List<Car> result = new Arraylist<>;
    result.add(retrieveCarsByBrand(brand)) // retrieveCarsByBrand omitted
    return result;
}

我的一位同事辩护说,方法getCarsBySingleBrand应该被重写为无效并使用List作为参数,这个列表将包含所有的汽车,如下所示:

private List<Car> getCarsByBrands(List<Brand> brands) {
    List<Car> result = new Arraylist<>;
    for(Brand brand : brands) {
        getCarsBySingleBrand(result, brand))
    }
    return result;
}

private void getCarsBySingleBrand(List<Car> cars, Brand brand) {
    cars.add(retrieveCarsByBrand(brand)) // retrieveCarsByBrand omitted
}

他认为这样消耗的内存更少,因为每次调用getCarsBySingleBrand方法时他都不会创建List。 我认为这是一种不必要的优化,并且是一种不好的做法,因为代码难以理解。

5 个回复

第二个选项可能更理想。

问题是第一种方式,不仅要为每个品牌制作另一个List对象,然后扔掉,但如果品牌有很多车,那么Java将调整列表的大小(初始化为默认大小)多次。 调整大小操作需要复制数组。 如果您多次调整大小,这可能会变得昂贵。

第二个选项只有一个列表,因为调整大小通常会使容量增加一倍,所以它应该比第一个选项调整更少的次数。

但是,这正在进行微观优化。 我不担心这种事情,除非你注意到性能问题,并做了分析以确定这是一个瓶颈。

如果您担心方法名称,我认为在名称中使用“get”这个词会让您失望,因为它通常意味着返回一些东西。 将其命名为addBrandOfCarsTo()可能会使其更像是一个句子:

for(Brand brand : brands) {
    addBrandOfCarsTo(result, brand));
}

两种选择都很好,主要取决于您的偏好:

  • 有些人更喜欢清晰(每个人都有自己的风格)。
  • 其他人更喜欢表演,不管它多么小。

如果您的情况,您也可以直接调用retrieveCarsByBrand并使用其结果:

private List<Car> getCarsByBrands(List<Brand> brands) {
    List<Car> result = new Arraylist<>;
    for(Brand brand : brands) {
        result.add(retrieveCarsByBrand(brand))
    }
    return result;
}

或者简化getCarsBySingleBrand并使用其结果:

private List<Car> getCarsByBrands(List<Brand> brands) {
    List<Car> result = new Arraylist<>;
    for(Brand brand : brands) {
        result.add(retrieveCarsByBrand(brand));
    }
    return result;
}

private List<Car> getCarsBySingleBrand(Brand brand) {
    return retrieveCarsByBrand(brand);
}

或者在清晰度和性能之间做出妥协,改变getCarsBySingleBrand的名称:

private List<Car> getCarsByBrands(List<Brand> brands) {
    List<Car> result = new Arraylist<>;
    for(Brand brand : brands) {
        getCarsBySingleBrand(result, brand))
    }
    return result;
}

private void addBrandCars(List<Car> cars, Brand brand) {
    cars.add(retrieveCarsByBrand(brand)) // retrieveCarsByBrand omitted


}

我想你可以使用这两个世界。 第二个的唯一优势是它消耗更少的内存。 如前所述,将函数方法改为void函数将增加清晰度,并将有助于单元测试(您可以模拟返回的值)。 我将如何做到这一点:

private List<Car> getCarsByBrands(List<Brand> brands) {
    List<Car> result = new Arraylist<>;
    for(Brand brand : brands) {
        getCarsBySingleBrand(result, brand))
    }
    return result;
}

private List<Car> addBrandCars(List<Car> cars, Brand brand) {
    cars.add(retrieveCarsByBrand(brand)) // retrieveCarsByBrand omitted
    return cars;
}

他可能是对的。

我们来解释为什么

所以在每个品牌第一个例子,你正在创建新的列表getCarsBySingleBrand方法,比你必须从新建列表在结果列表中添加被汽车getCarsByBrands

result.add(getCarsBySingleBrand(brand))

在这一行中,您只需从getCarsBySingleBrand获取列表,并将所有这些元素添加到结果中。

但在第二种情况下,您可以将汽车直接添加到getCarsByBrands 列表中 ,因此您可以减少操作。

另外说第一个例子消耗更多的内存是正确的。 但我认为这里更多的问题只是操作,而不是记忆。

结论

在我看来,第二种方法并不是一种糟糕的风格。 因此,如果需要,您可以进行此类优化。

正如@dkatzel所说,第二种选择可能更好。 但这只是因为在第一个选项中,在方法getCarsBySingleBrand(Brand brand) ,您不必要地将retrieveCarsByBrand(brand)结果复制到一个全新的ArrayList 这意味着在方法getCarsBySingleBrand(Brand brand)返回之前存在3个不同的列表:

  • 持有最终结果的那个
  • 带有单一品牌汽车的子列表,由retrieveCarsByBrand(brand)返回
  • 您用来复制retrieveCarsByBrand(brand)返回的列表的新ArrayList

如果@Narkha在第一个选项中建议,你通过不将retrieveCarsByBrand(brand)返回的汽车列表复制到新的ArrayList ,或者只是内联retrieveCarsByBrand(brand)方法,简化了方法getCarsBySingleBrand(brand) ,然后就内存消耗而言, 两种选择都是相同的 这是因为在这两种方法中,针对单个品牌检索的汽车列表将被复制到每个品牌保存最终结果的列表。 这意味着同时只存在2个列表:

  • 持有最终结果的那个
  • 带有单一品牌汽车的子列表,由retrieveCarsByBrand(brand)返回

正如其他人所说,几乎不需要这种优化。 但是,如果你使用Guava (你应该!),你应该知道有更好的方法来做到这一点。

private Iterable<Car> getCarsByBrands(List<Brand> brands) {
    Iterable<Iterable<Car>> carsGroupedByBrand = new Arraylist<>();
    for(Brand brand : brands) {
        carsGroupedByBrand.add(retrieveCarsByBrand(brand));
    }
    return Iterables.concat(carsGroupedByBrand);
}

该解决方案存储车,其中每个子列表保存每个品牌的轿车子列表的列表,并在年底装修的汽车子列表到一个单一的列表Iterable的汽车。 如果你真的需要返回List而不是Iterable ,那么你可以修改最后一行,如下所示:

    return Lists.newArrayList(Iterables.concat(carsGroupedByBrand));

这里的关键词是装饰 ,意味着不执行任何子列表的实际副本。 相反,会创建一个特殊用途的迭代器,它遍历第一个子列表的每个元素,当它到达终点时,它会自动透明地“跳转”到第二个子列表的第一个元素,直到它到达终点,所以on,直到它到达最后一个子列表的最后一个元素。 有关更多详细信息,请参阅Guava的Iterables.concat(...)方法文档

2 返回 方法的值

我需要从桌子上获取特定患者的所有约会,为此,我尝试 在我的约会类和表格中,我有如下字段,如PatientId,doctorid,约会日期, 在这里,我尝试在foreach循环中, 它的错误,它不能自动从数据库表约会转换为类约会。 我不知道该怎么做,任何人都可以在这里帮 ...

4 Void方法不能返回值

我正在网上关注CS106A讲座。 我正在阅读第12讲的代码,但是它给了我Eclipse中的错误。 这是我的代码。 似乎错误是因为我的main方法中的单词void。 我尝试删除main方法,但当然Java没有它就无法运行。 我是一个新手,没有人解释String[] args的真正 ...

5 带参数的void方法和没有参数的返回值方法? [关闭]

我正在用C#开发软件,我记得我读过一篇文章,内容如下: 设计一个类的方法: 使用带有参数的void方法来更改类实例的状态。 方法将对类的数据进行一些更改 使用不带任何参数的方法返回值 ,以便从类中检索数据 我再也找不到这篇文章,我想知道这样一个约定的好处和缺点, ...

6 从void方法内起一个返回值方法

我目前正在Moq'ing-或尝试Moq-将数据插入数据库的类。 我正在模拟两个接口,并通过使用DI将它们设置为以下“ Facade”类的构造函数。 目前,我所有的测试都可以运行和通过,但是我需要一些指导,以了解如何设置所示“ SaveServiceMessage”方法的返回布尔值。 ...

7 具有返回值的调用方法…参数

我正在寻找要放入钱包的参数的内容。CountMoney(); 如果有的话...与不返回的方法相比,我有一个思维障碍,即返回值的方法如何工作...我尝试了total ... double total .... um我尝试了进入程序,看看是否调试工具可以提供帮助,但没有任何提示。 任何指导都 ...

8 如何从Java中的void方法返回值

好的,所以我有这段代码,显然来自render方法的“ g = gd”并没有修改“ g”的字段值。 我如何才能使render方法修改字段g? 我想拥有一个图形字段,以便可以使用图形在render方法之外打印字符串,但是我真的不知道该怎么做。 编辑: 好的,这是整个类,我该 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM