将元素和集合连接成一个新的集合

时间:2017-05-04 16:34:21

标签: java collections

我有Collection个元素和一个元素。我希望我的getter函数看起来有点像这样

public List<Element> getElements(boolean includeOtherElement){

    if (includeOtherElement){
        return elements + otherElement; //Obviously this doesn't work, but I'm looking for something that would work like this
    }

    return elements;

}

有没有办法可以在一行中实现这种行为,例如使用Stream API或类似的东西?

编辑:

我已经意识到我不应该在getter方法中修改状态。

3 个答案:

答案 0 :(得分:1)

通常你不希望你的getter函数改变变量。我建议做temp = elements这样的事情来返回一个临时变量,并通过temp.add(otherElement)添加额外的元素。这样,您不会在仍然引发相同行为的同时更改当前变量。

答案 1 :(得分:1)

如果您不想将otherElement添加到元素列表但仍希望返回列表,则必须提供新列表。

简单方法:

public List<Element> getElements(boolean includeOtherElement){

    if (includeOtherElement){
        List<Element> extendedList = new ArrayList<>(elements);
        extendedList.add(otherElement);
        return extendedList;
    }

    return elements;
}

这将创建列表的浅表副本。

如果你真的想,你可以提供自己的列表实现,它将第一个索引委托给元素列表,最后一个索引委托给otherElement;

答案 2 :(得分:0)

我不确定这个答案是否适合您,但我认为这是API的一个很好的例子。它在特定情况下可能使用或不可用的原因是它取决于列表中额外元素的位置是否恒定。

假设您不想创建列表副本,因为您实际上想要调用getter的人能够修改列表。或者,假设您只是不想制作列表的防御性副本,可能是因为列表非常非常大。在这些情况下,您不希望在列表中添加或删除额外元素,您希望返回列表的视图,其中包含或排除额外元素。

使用List.subList(int, int)方法,现有API实际上可以实现。 subList不会创建副本,例如String.substring(...)。相反,返回的子列表是可变的(如果原始列表是),并且子列表的更改显示到原始列表。

(虽然我应该注意,如果支持列表在结构上被修改,子列表的语义将变为未定义,即您不应在保留对子列表的引用的同时添加/删除原始列表。如果您更改了原始列表通过子列表以外的引用,您必须创建一个新的子列表。)

所以你可以做的是保留一个包含所有元素的完整列表,然后返回一个范围的子列表,该子列表排除了你不想返回的元素。

如果调用getter的代码不能改变列表,也可以与Collections.unmodifiableList(List)一起使用。

以下是一个显示此操作的示例:

import java.util.*;

class Example {
    public static void main (String[] args) {
        Example e = new Example();
        List<Object> sub = e.getList(false);
        // sublist is [1, 2, 3]
        System.out.printf("sublist is %s%n", sub);
        sub.add(0, -1);
        sub.add(1,  0);
        sub.add(5);
        // sublist is [-1, 0, 1, 2, 3, 5]
        System.out.printf("sublist is %s%n", sub);
        List<Object> all = e.getList(true);
        // full list is [element0, -1, 0, 1, 2, 3, 5]
        System.out.printf("full list is %s%n", all);
        // As a side-note, this sequence of calls is
        // e.g. what you aren't supposed to do:
        // all.add(something); // <- structural modification
        // sub.add(another);   // <- this is undefined
        // You have to make a new sublist first:
        // sub = e.getList(false);
        // sub.add(another);   // <- this is fine now
    }

    List<Object> objects = new ArrayList<Object>();
    Example() {
        objects.add("element0");
        objects.add(1);
        objects.add(2);
        objects.add(3);
    }

    List<Object> getList(boolean includeElement0) {
        if (includeElement0) {
            return objects;
        } else {
            return objects.subList(1, objects.size());
        }
    }
}

以下是Ideone上的示例:http://ideone.com/PloZCh

此外,虽然不返回List,但可以通过返回Stream来完成此操作:

Stream<E> stream = list.stream();
if (includeOtherElement) {
    return Stream.concat(stream, Stream.of(otherElement));
} else {
    return stream;
}

我想这可能是在Java 8中做这种事情的规范方式。