在从带参数的void方法中打印值或将值返回给方法调用者并将其打印到方法调用者之间的哪种最佳做法(如果有)? 例如,第一个代码摘录是前者,而第二个代码摘录是后者: 和 ...
提示:本站收集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。 我认为这是一种不必要的优化,并且是一种不好的做法,因为代码难以理解。
第二个选项可能更理想。
问题是第一种方式,不仅要为每个品牌制作另一个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(...)方法文档 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.