Java: obtenha o primeiro item de uma coleção


277

Se eu tiver uma coleção, como Collection<String> strs, como posso retirar o primeiro item? Eu poderia simplesmente chamar um Iterator, pegar o primeiro next()e depois jogar Iteratorfora. Existe uma maneira menos dispendiosa de fazer isso?


1
Claro que pode haver uma maneira melhor para acessar o primeiro elemento se você sabe a classe recipiente implementação ...
Rooke

Generalização para qualquer índice: stackoverflow.com/questions/1047957/…
Ciro Santilli #: 23315

1
Parece que você precisa do Queue.peek ()
Johannes

Respostas:


131

Iterables.get (yourC, indexYouWant)

Porque, na verdade, se você estiver usando coleções, deve usar coleções do Google.


7
Isso faz a mesma coisa, apenas verifica se é uma lista primeiro e obtém o índice, se for. Ele também possui algum código para tentar falhar mais rapidamente em uma coleção real (ou seja, se o índice for muito grande, ele tentará descobrir isso sem iterar a coisa toda e lançar a exceção no final).
Yishai

1
Honestamente, em termos de desempenho, pode ser um pouco mais lento que c.iterator (). Next () - mas o código é muito mais claro e simples de modificar.
4301 Carl

2
Eu certamente concordo que é mais limpo, mas o OP foi um desperdício, mas acho que, desde que sua resposta foi aceita, era isso que era desejado.
Yishai

8
Para aqueles que ainda estão chegando aqui: acho que a resposta dos jheddings é provavelmente a melhor resposta "faça-o", embora prefira os @ DonaldRaab (no final da página) para os casos em que já estou usando a biblioteca do GC. Minha resposta é realmente para o caso em que se pode escrever com flexibilidade para mais tarde (digamos, se alguém decidir que o segundo elemento é o novo calor).
24243 Carl

4
Às vezes, você está apenas usando um código que usa Coleções, então não há muito o que fazer.
precisa saber é o seguinte

436

Parece que é a melhor maneira de fazer isso:

String first = strs.iterator().next();

Ótima pergunta ... No começo, parece uma supervisão para o Collection interface.

Observe que "first" nem sempre retorna a primeira coisa que você coloca na coleção e pode fazer sentido apenas para coleções ordenadas. Talvez seja por isso que não há uma get(item)ligação, pois a ordem não é necessariamente preservada.

Embora possa parecer um pouco inútil, pode não ser tão ruim quanto você pensa. Ele Iteratorrealmente contém apenas informações de indexação na coleção, e não geralmente uma cópia de toda a coleção. A invocação desse método instancia o Iteratorobjeto, mas essa é realmente a única sobrecarga (não é como copiar todos os elementos).

Por exemplo, olhando para o tipo retornado pelo ArrayList<String>.iterator()método, vemos que é ArrayList::Itr. Esta é uma classe interna que apenas acessa os elementos da lista diretamente, em vez de copiá-los.

Apenas certifique-se de verificar o retorno, iterator()pois ele pode estar vazio ou nulldependendo da implementação.


3
É importante observar que esse "truque" só funciona quando a coleção realmente possui conteúdo. Se estiver vazio, o iterador pode retornar um erro, no qual é necessário verificar o tamanho da coleção com antecedência.
Spaceemotion #

20
Essa deve ser a resposta correta. Não entendo por que a resposta é sempre "use outra biblioteca!" .
Kuzeko

E o segundo elemento da coleção? Por que first-> next () não funciona? O que devo fazer? Obrigado!
Pb772

não é seguro o suficiente, não é garantido que a coleção sempre aponte para o primeiro elemento.
Next Developer

84

No java 8:

Optional<String> firstElement = collection.stream().findFirst();

Para versões mais antigas do java, existe um método getFirst no Guava Iterables :

Iterables.getFirst(iterable, defaultValue)

6
A solução java 8 é especialmente útil, pois lida com o caso em que a coleção está vazia normalmente.
SpaceTrucker 16/02

4
Não é bom. Você adiciona sobrecarga de stream () para obter um get (0) só porque tem preguiça de escrever 4 linhas de código. if (! CollectionUtils.isEmpty (productList)) {return Optional.of (productList.get (0)); } return Optional.empty ();
RS

Eu não tenho getFirstmétodo disponível. Existem gete getLastmétodos
user1209216

4
@RS e o que acontece se você não puder chamar productList.get (0), pois é uma coleção ..? (De acordo com a pergunta do OP)
Denham Coote

40

Não existe o "primeiro" item em um Collectionporque é ... bem, simplesmente uma coleção.

No método Collection.iterator () do Java doc :

Não há garantias quanto à ordem em que os elementos são retornados ...

Então você não pode.

Se você usar outra interface, como Lista , poderá fazer o seguinte:

String first = strs.get(0);

Mas diretamente de uma coleção, isso não é possível.


11
Eu não acho que get(int n)é definido paraCollection
Nick Heiner

2
Você está certo, eu sinto falta desse ponto. Eu atualizei a resposta. Você não pode! (a menos que a coleção é implementado por alguma classe underlaying que permite que fornece a garantia)
OscarRyz

get não está na interface Collection
Andy Gherna 4/11/2009

21
Oscar, acho que você está exagerando o caso. O primeiro elemento de uma coleção pode ser arbitrário em alguns casos como o HashSet, mas está bem definido: é .iterator (). Next (). Também é estável , em todas as implementações de coleções que eu já vi. (relacionados: nota que, enquanto Set não garante fim, cada subtipo de Situado no JDK exceto HashSet faz.)
Kevin Bourrillion

3
Pode ser, mas considere o caso, quando você adiciona um novo elemento à coleção, não sabe (pela interface) se esse elemento é o primeiro, o último ou se ele seria inserido no meio. Para resultados precisos, você deve usar outra interface. No entanto, provavelmente o que a Rosarch precisa é o primeiro elemento, não importa o quê. Conhecer a coleção subjacente pode ajudar, mas impede que você a altere.
OscarRyz 04/11/2009

4

Parece que sua coleção quer ser parecida com uma lista, então eu sugiro:

List<String> myList = new ArrayList<String>();
...
String first = myList.get(0);

2

No Java 8, você tem muitos operadores para usar, por exemplo, limite

     /**
 * Operator that limit the total number of items emitted through the pipeline
 * Shall print
 * [1]
 * @throws InterruptedException
 */
@Test
public void limitStream() throws InterruptedException {
    List<Integer> list = Arrays.asList(1, 2, 3, 1, 4, 2, 3)
                               .stream()
                               .limit(1)
                               .collect(toList());
    System.out.println(list);
}

2
A resposta de @Vitalii Fedorenko stackoverflow.com/a/18165855/1562662 é melhor.
precisa

2

O Goiaba fornece um onlyElement Collector, mas só o usa se você espera que a coleção tenha exatamente um elemento.

Collection<String> stringCollection = ...;
String string = collection.stream().collect(MoreCollectors.onlyElement())

Se você não tiver certeza de quantos elementos existem, use findFirst.

Optional<String> optionalString = collection.stream().findFirst();

1

Você pode fazer um casting. Por exemplo, se existe um método com esta definição e você sabe que esse método está retornando uma Lista:

Collection<String> getStrings();

E depois de invocá-lo, você precisa do primeiro elemento, pode fazê-lo assim:

List<String> listString = (List) getStrings();
String firstElement = (listString.isEmpty() ? null : listString.get(0));

0

Se você souber que a coleção é uma fila, poderá convertê-la em uma fila e obtê-la facilmente.

Existem várias estruturas que você pode usar para obter o pedido, mas precisará convertê-lo.


Concordo que, se você não quiser iterar, não use coleção. Use alguma outra interface mais específica.
911 Adeel Ansari

1
Eu me pergunto, no entanto ... digamos que os dados subjacentes reais sejam um SortedSet, portanto, a ordem faz sentido, mas você só tem uma visão de coleção (por uma razão não boba, digamos); se você converter a coleção em uma lista, fila etc. e tentar obter / poll / etc, o desastre ocorre? Da mesma forma, se a estrutura subjacente for uma Lista, e assim por diante.
Carl Carl

@ Cal - Eu não tentei, mas se você converter uma coleção em um tipo muito diferente do que era originalmente, deverá receber um erro, mas, eu não tentei, para poder estar errado.
James Black

0

Depende totalmente de qual implementação você usou, se arraylist linkedlist ou outras implementações de set.

se estiver definido, você poderá obter diretamente o primeiro elemento, o loop pode ser um truque sobre a coleção, criar uma variável de valor 1 e obter valor quando o valor do sinalizador for 1 após a interrupção desse loop.

se for a implementação da lista, será fácil definir o número do índice.


0

Maneira funcional:

public static <T> Optional<T> findFirst(List<T> result) {
    return Optional.ofNullable(result)
            .map(List::stream)
            .flatMap(Stream::findFirst);
}

preservação de snippet de código acima de NullPointerException e IndexOutOfBoundsException


1
Sua escolha de List<T>não satisfazer a condição de que ele deve trabalhar para um Collection<String>, mas é claro que pode ser corrigido usando Collection<T>, com a alteração adicional: .map(Collection::stream).
Scratte 30/03

-2

Você poderia fazer isso:

String strz[] = strs.toArray(String[strs.size()]);
String theFirstOne = strz[0];

O javadoc para Collection fornece a seguinte advertência por ordem dos elementos da matriz:

Se essa coleção garantir qualquer ordem de retorno de seus elementos por seu iterador, esse método deverá retornar os elementos na mesma ordem.


2
Isso cria uma nova matriz String, muito mais cara que a criação de um iterador.
9119 Jim Ferrans

Sim, pensei nisso depois de postar isso. Independentemente do método usado, o pedido depende da implementação subjacente da coleção. "Primeiro" se torna um termo relativo. No entanto, a maneira de fazer iterador () provavelmente é melhor na maioria dos casos.
Andy Gherna 4/11/2009

2
Eu vim aqui porque esta era a solução que eu tinha e achei feia.
precisa saber é o seguinte
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.