Pergunta

muitas vezes eu fazer um campo de coleta unmodifiable antes de devolvê-lo a partir de um método getter:

private List<X> _xs;
....
List<X> getXs(){
  return Collections.unmodifiableList(_xs);
}

Mas eu não consigo pensar em uma maneira conveniente de fazer isso se o X acima é em si uma lista:

private List<List<Y>> _yLists;
.....
List<List<Y>> getYLists() {
  return Collections.unmodifiableList(_yLists);
}

O problema no exemplo acima é claro que, apesar do cliente não pode modificar a lista de listas, pode adicionar / excluir Y objetos a partir das listas incorporadas.

Qualquer pensamento?

Foi útil?

Solução

O melhor que eu poderia vir acima com usos ForwardingList do Google Collections . Comentários são bem-vindos.

private static <T> List<List<T>> unmodifiableList2(final List<List<T>> input) {
    return Collections.unmodifiableList(new ForwardingList<List<T>>() {
        @Override protected List<List<T>> delegate() {
            return Collections.unmodifiableList(input);
        }
        @Override public List<T> get(int index) {
            return Collections.unmodifiableList(delegate().get(index));
        }
    });
}

Outras dicas

Infelizmente, não há nenhuma maneira fácil de obter profunda const-ness em java. você teria que cortar em torno dele, sempre certificando-se de que a lista dentro da lista também é unmodifiable.

Eu estaria interessado também saber qualquer solução elegante.

As coleções Clojure (mapa, conjunto, lista, vetor) podem ser encaixados e são imutáveis ??por padrão. Para java puro, não existe essa biblioteca:

http://code.google.com/p/pcollections/

Se você olhar para a implementação dos (...) métodos Collections.unmodifiable *, você pode ver que eles só embrulhar a coleção. Fazendo um utilitário profunda na mesma forma deve ser factível.

A desvantagem desta situação é que ele acrescenta chamada de método extra para o acesso recolha e assim afeta o desempenho.

Se o seu único objetivo aqui é fazer valer o encapsulamento, uma solução clássica é usar clone () ou similar para retornar uma estrutura que não é o estado interno do objeto. Isto, obviamente, só funciona se todos os objetos podem ser clonados, e se a estrutura copiada é pequeno o suficiente.

Se esta é uma estrutura de dados bastante comumente usado, outra opção é fazer a API que acessa-lo mais concreto, para que você tenha um controle mais detalhado sobre as chamadas específicas. Escrever sua própria implementação List, como acima é um maneira de fazer isso, mas se você pode restringir as chamadas para casos de uso específicos, você pode expor APIs de acesso específicos em vez da interface List.

Apenas no caso de alguém está interessado aqui é uma solução simples:

    public List<List<Double>> toUnmodifiable(List<List<Double>> nestedList) {
        List<List<Double>> listWithUnmodifiableLists = new ArrayList<>();
            for (List<Double> list : nestedList) {              
                listWithUnmodifiableLists
                    .add(Collections.unmodifiableList(list));
            }
        return Collections.unmodifiableList(listWithUnmodifiableLists);
    }

Isto pode ser usado, por exemplo, como uma solução, se u deseja expor uma lista com um método getList (), você pode retornar:. ToUnmodifiable (mNestedList), onde mNestedList a lista privada na classe

Eu encontrei pessoalmente este útil ao implementar uma classe usada para analisar com Gson no Android, uma vez que não faz sentido para ser capaz de modificar uma resposta, neste caso, o JSON de-serializado, eu usei esse método como um maneira de expor a lista com um getter e fez com que a lista não vai ser modificado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top