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.