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?

Nick Heiner
fonte
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.

Carl
fonte
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.

casamentos
fonte
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)
Vitalii Fedorenko
fonte
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.

OscarRyz
fonte
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);
Jim Ferrans
fonte
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);
}
Paulo
fonte
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();
cambunctious
fonte
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));
Nacho Soriano
fonte
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.

James Black
fonte
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.

Sindhoo Oad
fonte
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

Farhad Baghirov
fonte
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.

Andy Gherna
fonte
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