我经常发现自己编写的代码可以从多个子列表中构建一个List。举个简单的例子假设您有一个需要验证List的List。写这个(命令性地)的一种方法是:
import static com.google.common.collect.Lists.newArrayList;
import java.util.List;
public class Product {
private String name;
private int height;
public static List<String> validateList(List<Product> products) {
List<String> result = newArrayList();
valideListSize(products, result);
for (Product product : products) {
product.validate(result);
}
return result;
}
private static void valideListSize(List<Product> products,
List<String> result) {
if (products.size() > 1000) {
result.add("List too large");
}
}
private void validate(List<String> result) {
if (name.length() > 30) {
result.add("Name contains too many characters");
}
if (height > 40) {
result.add("Product too high");
}
}
}
然而,为了简化/维护/重用,我不喜欢将验证单个产品的逻辑与将验证结果列表添加到另一个现有列表相关联。我还认为改变参数会导致更难调试代码。所以我更喜欢更实用的风格。目前我通常会这样写(使用来自Google Guava的newArrayList):
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import java.util.List;
public class Product {
private String name;
private int height;
public static List<String> validateList(List<Product> products) {
List<String> result = newArrayList();
result.addAll(valideListSize(products));
for (Product product : products) {
result.addAll(product.validate());
}
return result;
}
private static List<String> valideListSize(List<Product> products) {
if (products.size() > 1000) {
return singletonList("List too large");
}
return emptyList();
}
private List<String> validate() {
List<String> result = newArrayList();
if (name.length() > 30) {
result.add("Name contains too many characters");
}
if (height > 40) {
result.add("Product too high");
}
return result;
}
}
这会创建许多寿命很短的小型arraylists,其中许多通常都是空的(没有验证错误)。 这种代码在实践中效率低下还是可以在生产环境中使用这种风格? 有没有更有效的方法(可能使用Guava)做我想做的事情,同时仍然保持代码干净,易于阅读并符合Java最佳实践?
您作为专业Java开发人员会做什么?
编辑:在第一条评论中看到我的回答为什么我更喜欢第二种方式。我更喜欢代码可维护性/可读性而不是过早优化,但因为我在日常编程中看到了很多这种模式,我想知道是否有一种简单的方法至少是干净的。 如何使用某种联合列表视图,例如Iterables.concat?或者这也创造了许多中间类?
答案 0 :(得分:0)
您可以使用Disjoint-set data structure(也称为union-find数据结构)有效地完成此操作。在线有几种实现方式,例如here
答案 1 :(得分:0)
回答我自己的问题:即使在单一产品验证方法中创建了许多新列表,Java也能很好地提高性能。我定时验证了30万件产品的清单(经过预热)。
传递一个Arraylist的第一个实现需要275ms。使用LinkedList需要300ms。 可以创建中间ArrayLists的第二个实现需要760ms。使用LinkedList需要580ms。使用Guava的ImmutableList构建器需要1150ms。
所以我想我会继续使用我的第二种方法(也许使用LinkedList来处理不需要随机访问的小型列表)。