【问题标题】:Multiple lists or list and getSublist() (Java)多个列表或列表和 getSublist() (Java)
【发布时间】:2016-11-20 03:41:23
【问题描述】:

我有一个抽象类“实体”和实现不同接口的对象(扩展“实体”)。 我还有一个包含所有这些不同对象的 ArrayList。

现在,如果我需要访问实现某个接口的所有实体(以使用其方法),我使用以下方法(它返回实现接口“IDirectFire”的“实体”的过滤列表):

public ArrayList<IDirectFire> getDirectFireSublist() {//direct fire sublist
    ArrayList<IDirectFire> sublist = new ArrayList();
    entities.stream().filter((it) -> (it instanceof IDirectFire)).forEach((it) -> {
        sublist.add((IDirectFire) it);
    });
    return sublist;
}

现在我的问题: 我应该进一步使用这种方法,还是应该创建一个新的 ArrayList,它存在于“实体”之外并且每次“实体”更改时我都需要手动更新?

我需要经常更新“实体”,所以我不确定存储多个子列表并在每次“实体”更改时都更新它们是否更有效,或者我是否应该继续使用过滤“实体”并应用的方法这些子列表的方法。请记住,这些子列表也将在其他方法中循环使用,例如:

private void resetFirestatusIDF() {//reset firestatus (IDirectFire)
    getDirectFireSublist().stream().forEach((it) -> {
        it.dfHasFired(false);
    });}

这可行吗? 提前致谢!

【问题讨论】:

  • 一般来说,应该尽量避免使用instanceof,因为它被认为是一种“设计气味”

标签: java arraylist filter sublist


【解决方案1】:

现在我的问题是:我应该进一步使用这种方法还是应该创建一个新的 ArrayList,它存在于“实体”之外并且每次“实体”更改时我都需要手动更新?

出于什么原因您想要复制“实体”数据?

1) 您只能将它们放在专用列表中。在这种情况下,您不再需要 getDirectFireSublist()。

2) 您可以在两个列表之间共享它们而无需复制它们。 在这种情况下,您必须更新添加和删除的实体元素,因为只会更新修改的元素。但是实现起来比较直接。

【讨论】:

  • 新列表不会重复,而是过滤后的“实体”作为自己的列表,所以是的,我的意思是一个专用列表。谢谢!
【解决方案2】:

wakjah 在评论中提到instanceof 有点设计味道。考虑到这一点,另一种解决方案是使用访问者模式。

public abstract class Entity {
    public abstract void acceptVisitor(EntityVisitor visitor);
    ...
}

public interface IDirectFire {
    default acceptVisitor(EntityVisitor visitor) {
        visitor.visit(this);
    }
    ...
}

public class ResetFireStatusVisitor implements EntityVisitor {
    public void visit(IDirectFire directFireEntity) {
        directFireEntity.dfHasFired(false);
    }
}

然后,遍历项目:

entities.forEach(entity -> entity.acceptVisitor(new ResetFireStatusVisitor()));

ResetFireStatusVisitor 在任何实现 IDirectFire 的东西上调用 dfHasFired(false)。在EntityVisitor 中,您可以为Entity 的其他子类型指定默认无操作实现。

我不建议您在简单的情况下这样做,但对于大规模设计,这可能是解决这个问题的有用答案。另一方面,它可能不会——这种模式也有它的设计味道。

【讨论】:

  • 请问为什么 instanceof 是设计的味道?我绝对看到了访客的用处,只是好奇。 instanceof 更容易出错吗?非常感谢!
  • 主题范围太大,无法在评论中涵盖,但那里有很多讨论。这是最热门的搜索结果:stackoverflow.com/questions/20589590/…
  • 是的,对不起,显然是一个很大的主题,我会做一些搜索。感谢您的链接和您的帮助!
【解决方案3】:

如果您只需要遍历项目的子集,那么创建新列表是一种浪费。只需返回过滤后的 Stream。

public Stream<IDirectFire> getDirectFire() {
    return entities.stream().filter((it) -> (it instanceof IDirectFire));
}

您也可以使用 Guava 并返回过滤后的 Iterable

public Iterable<IDirectFire> getDirectFire() {
    return FluentIterable.from(entities).filter(IDirectFire.class);
}

然后,循环遍历其他地方的项目:

private void resetFirestatusIDF() {
    getDirectFire().forEach((it) -> it.dfHasFired(false));
}

【讨论】:

  • 谢谢,虽然我目前没有使用 Guava。会看看的!
  • Guava 中的 filter(Class&lt;?&gt;) 方法非常适合您正在做的事情,但除此之外,Stream 方法同样出色。它们都有一个forEach 方法,这意味着循环示例对于两者都是相同的。
【解决方案4】:

最好过滤它们。它将以可忽略不计的性能下降为代价创建更清晰易懂的代码,除非您过滤数百万个元素,否则应该可以忽略不计。

我注意到的第二件事是您对代码片段 1 的流式使用。我会推荐您和替代方法:

> public ArrayList<IDirectFire> getDirectFireSublist() {
>      return entities.stream().filter((it) -> (it instanceof IDirectFire)).collect(Collectors.toList());
> }

【讨论】:

  • 非常感谢!我不确定它会对性能产生多大影响。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多