Por que o método removeRange () do AbstractList do Java é protegido?

98

Alguém tem alguma ideia, por que o método removeRange em AbstractList (e também em ArrayList ) é protected? Parece uma operação bem definida e útil, mas ainda assim, para usá-la, somos forçados a criar uma subclasse da implementação de List.

Existe alguma justificativa oculta? Parece bastante inexplicável para mim.

Joonas Pulakka
fonte

Respostas:

163

Sim, porque não é assim que você remove um intervalo de um código externo. Em vez disso, faça o seguinte:

list.subList(start, end).clear();

Isso realmente chama removeRangeos bastidores.


O OP pergunta por que removeRangenão faz parte da ListAPI pública. O motivo é descrito no Item 40 do Effective Java 2 ed, e eu o cito aqui:

Existem três técnicas para encurtar listas de parâmetros excessivamente longas. Uma é dividir o método em vários métodos, cada um dos quais requer apenas um subconjunto dos parâmetros. Se feito de forma descuidada, isso pode levar a muitos métodos, mas também pode ajudar a reduzir a contagem de métodos, aumentando a ortogonalidade. Por exemplo, considere a java.util.Listinterface. Ele não fornece métodos para encontrar o primeiro ou o último índice de um elemento em uma sublista, pois ambos exigiriam três parâmetros. Em vez disso, ele fornece o subListmétodo, que usa dois parâmetros e retorna uma visualização de uma sublista. Este método pode ser combinado com os métodos indexOfou lastIndexOf, cada um dos quais tem um único parâmetro, para produzir a funcionalidade desejada. Além disso, osubListO método pode ser combinado com qualquer método que opere em uma Listinstância para realizar cálculos arbitrários em sublistas. A API resultante tem uma relação potência-peso muito alta.

Pode-se argumentar que removeRangenão tem tantos parâmetros e, portanto, provavelmente não é um candidato para esse tratamento, mas dado que há uma maneira de invocar removeRangepor meio do subList, não há razão para sobrecarregar a Listinterface com um método redundante.


A AbstractList.removeRangedocumentação diz:

Este método é chamado pela clearoperação nesta lista e suas subListas. Substituir este método para tirar proveito dos elementos internos da implementação da lista pode melhorar substancialmente o desempenho da clearoperação nesta lista e em suas subListas.

Além disso, consulte a implementação do OpenJDK de AbstractList.cleare SubList.removeRange.

Chris Jester-Young
fonte
9
Ok, pode ser feito dessa forma, mas por quê ? Parece estranho. Elementos individuais podem ser removidos da lista diretamente, por que não vários elementos então?
Joonas Pulakka de
1
@Joonas: O item 40 de Effective Java, 2ª ed descreve a justificativa para isso. Vou colar na seção relevante, caso você não tenha o livro.
Chris Jester-Young
21
+1 (pergunta respondida). No entanto, só porque uma justificativa é fornecida, não significa que faça sentido. O processo de encurtamento de listas de parâmetros dificulta a capacidade dos desenvolvedores de entender as operações disponíveis em uma API, o que funciona diretamente contra o motivo pelo qual as listas foram encurtadas em primeiro lugar.
Sam Harwell
3
Tão típico para java. Vamos torná-lo mais complicado e menos eficaz.
Tomáš Zato - Reintegrar Monica em
2
como observação lateral, você notou que removeRangechama arraycopydesnecessariamente quando a ArrayListversão é usada em um intervalo que vai até o final da lista? hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e2117e30fb39/src/share/… o numMovedé 0, então todo o código arraycopy poderia ter sido colocado em um único if(como feito em remove); a diferença é que a) arraycopy é uma chamada nativa, incorrendo em uma sobrecarga, b) arraycopy sempre verifica os parâmetros de correção stackoverflow.com/questions/12594046/…