Java: Отримайте перший предмет із колекції


277

Якщо у мене є колекція, наприклад Collection<String> strs, як я можу отримати перший предмет? Я міг просто зателефонувати Iterator, взяти його спочатку next(), а потім викинути Iterator. Чи є менш марнотратний спосіб це зробити?


1
Звичайно, може бути кращий спосіб отримати доступ до першого елемента, якщо ви знаєте клас контейнерів-реалізаторів ...
Rooke

Узагальнення для будь-якого індексу: stackoverflow.com/questions/1047957 / ...
Чіро Сантіллі郝海东冠状病六四事件法轮功

1
Звучить, вам потрібен Queue.peek ()
Йоганнес

Відповіді:


131

Iterables.get (вашC, indexYouWant)

Тому що, якщо ви користуєтеся колекціями, ви повинні використовувати колекції Google.


7
Це робить те ж саме, він просто перевіряє, чи є він спочатку списком, і отримує за індексом, якщо він є. У нього також є якийсь код, який намагається швидше вийти з ладу на фактичній колекції (тобто, якщо індекс занадто великий, він намагається зрозуміти це, не повторюючи всю справу і викидаючи виняток наприкінці).
Ісіхай

1
Чесно кажучи, продуктивність може бути трохи повільнішою, ніж c.iterator (). Next () - але код набагато чіткіший і простіший для зміни.
Карл

2
Я, звичайно, погоджуюся, що вона чистіша, але ОП стосувалася марнотратства, але, мабуть, оскільки ваша відповідь була прийнята, саме так і хотілося.
Yishai

8
Для тих, хто досі приїжджає сюди: я вважаю, що відповідь jheddings - це, мабуть, найкраща відповідь "закінчіть це", хоча я б віддав перевагу @ DonaldRaab (внизу сторінки) у випадках, коли я вже використовую бібліотеку GC. Моя відповідь насправді стосується випадку, коли можна писати гнучко писати на потім (скажімо, якщо хтось вирішить, що другим елементом є нова гарячість).
Карл

4
Іноді ви просто використовуєте код, який використовує колекції, тому робити не багато чого.
erickrf

436

Схоже, це найкращий спосіб зробити це:

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

Чудове запитання ... Спочатку це здається наглядом за Collectionінтерфейсом.

Зауважте, що "first" не завжди повертає перше, що ви помістили в колекцію, і може мати сенс лише для замовлених колекцій. Можливо, тому немає get(item)дзвінка, оскільки замовлення не обов'язково зберігається.

Хоча це може здатися трохи марнотратним, це може бути не так вже й погано, як ви думаєте. IteratorДійсно тільки містить інформацію індексації в колекції, як правило , НЕ копію всієї колекції. Викликання цього методу створює Iteratorоб'єкт, але це справді єдиний накладний (не як копіювання всіх елементів).

Наприклад, дивлячись на тип, який повертається ArrayList<String>.iterator()методом, ми бачимо, що він є ArrayList::Itr. Це внутрішній клас, який просто отримує доступ до елементів списку безпосередньо, а не копіює їх.

Просто не забудьте перевірити повернення, iterator()оскільки воно може бути порожнім або nullзалежно від реалізації.


3
Важливо зазначити, що цей «трюк» працює лише тоді, коли колекція насправді містить вміст. Якщо порожній, ітератор може повернути помилку, в якій потрібно заздалегідь перевірити розмір колекції.
spaceemotion

20
Це має бути правильна відповідь. Я не розумію, чому відповідь завжди "використовувати іншу бібліотеку!" .
Кузеко

Як щодо другого елемента колекції? Чому перший-> наступний () не працює? Що я повинен зробити? Дякую!
pb772

недостатньо безпечний, не гарантується, що колекція завжди вказуватиме на 1-й елемент.
Наступний розробник

84

У java 8:

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

Для старих версій Java існує метод getFirst у програмі Guava Iterables :

Iterables.getFirst(iterable, defaultValue)

6
Рішення java 8 особливо корисне, оскільки воно витончено обробляє випадок, коли колекція порожня.
SpaceTrucker

4
Не добре. Ви додаєте накладні витрати потоку (), щоб отримати (0) тільки тому, що вам лінь написати 4 рядки коду. if (! collectionUtils.isEmpty (productList)) {return Optional.of (productList.get (0)); } return Необов’язково.порожня ();
RS

У мене немає getFirstметоду. Є getі getLastметоди
user1209216

4
@RS і що станеться, якщо ви не можете зателефонувати productList.get (0), оскільки це колекція ..? (Згідно з питанням про ОП)
Denham Coote

40

Не існує такого поняття, як "перший" предмет у a, Collectionтому що це .. ну просто колекція.

З методу Collection.iterator () документації Java-документа :

Немає гарантій щодо порядку повернення елементів ...

Тож ви не можете.

Якщо ви використовуєте інший інтерфейс, такий як List , ви можете зробити наступне:

String first = strs.get(0);

Але безпосередньо з колекції це неможливо.


11
Я не думаю get(int n), що визначено для цьогоCollection
Нік Хайнер

2
Ти маєш рацію, я сумую за цим моментом. Я оновив відповідь. Ти не можеш! (Якщо збір не реалізується який - то нижчого класу , що дозволяє забезпечує гарантію)
OscarRyz

get не в інтерфейсі колекції
Andy Gherna

21
Оскаре, я думаю, ви завищуєте справу. Перший елемент колекції може бути довільним у кількох випадках, як HashSet, але він чітко визначений: це .iterator (). Next (). Він також стабільний , у кожній реалізації колекції, яку я коли-небудь бачив. (Пов'язані з : зверніть увагу , що в той час як набір не гарантує порядок, кожен підтип Набір в JDK крім HashSet робить.)
Kevin Bourrillion

3
Це може бути, але врахуйте випадок, коли ви додаєте новий елемент у колекцію, ви не знаєте (за інтерфейсом), якщо цей елемент є першим, останнім чи він буде вставлений посередині. Для точних результатів слід використовувати інший інтерфейс. І все-таки, мабуть, те, що потрібно Росарху, є першим елементом, незважаючи ні на що. Знання нижньої колекції може допомогти, але це заважає вам змінити її.
OscarRyz

4

Здається, що ваша колекція хоче бути схожою на список, тому я б запропонував:

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

2

У Java 8 у вас є кілька операторів, наприклад, ліміт

     /**
 * 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
Відповідь @Vitalii Федоренко stackoverflow.com/a/18165855/1562662 краще.
Чакко Матвій

2

Guava надає onlyElement Collector, але використовуйте його лише в тому випадку, якщо ви очікуєте, що колекція має саме один елемент.

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

Якщо ви не впевнені, скільки елементів є, скористайтеся findFirst.

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

1

Можна робити кастинг. Наприклад, якщо існує один метод із цим визначенням, і ви знаєте, що цей метод повертає список:

Collection<String> getStrings();

А після виклику цього вам потрібен перший елемент, ви можете це зробити так:

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

0

Якщо ви знаєте, що колекція - це черга, ви можете кинути її в чергу і легко отримати її.

Існує кілька структур, якими ви можете скористатися, щоб отримати замовлення, але вам потрібно буде передати його.


Я погоджуюся, якщо ви не хочете повторити, не використовуйте колекцію. Замість цього використовуйте інший більш конкретний інтерфейс.
Адель Ансарі

1
Мені цікаво, хоча ... скажімо, фактичні основні дані - це SortedSet, тому замовлення має сенс, але у вас є лише перегляд колекції (з приводу нерозумної причини, скажімо); якщо ви кидаєте колекцію до списку, черги тощо, і намагаєтесь отримати / опитування / тощо, чи настане лихо? Так само, якщо базовою структурою є Список, так далі, і так далі.
Карл

@Cal - я не пробував цього, але якщо ви передали колекцію зовсім іншого типу, ніж це було спочатку, ви повинні отримати помилку, але, я не пробував, тому я можу помилитися.
Джеймс Блек

0

Це повністю залежить від того, яку реалізацію ви використовували, чи пов’язаний список архівців, чи інші реалізації набору.

якщо він встановлений, ви можете безпосередньо отримати перший елемент, їх може бути фокус циклу над колекцією, створити змінну значення 1 та отримати значення, коли значення прапора дорівнює 1 після того, як перервати цю петлю.

якщо це реалізація списку, то це легко, визначивши номер індексу.


0

Функціональний спосіб:

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

вище збереження фрагмента коду від NullPointerException та IndexOutOfBoundsException


1
Ваш вибір List<T>не задовольняє умову , що він повинен працювати для Collection<String>, але, звичайно, може бути закріплена з допомогою Collection<T>, з додатковим зміною: .map(Collection::stream).
Scratte

-2

Ви можете це зробити:

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

Javadoc для Collection надає наступне вказівка ​​wrt впорядкування елементів масиву:

Якщо ця колекція дає будь-які гарантії того, в якому порядку її елементи повертаються ітератором, цей метод повинен повернути елементи в тому ж порядку.


2
Це створює новий String масив, набагато дорожче, ніж створення ітератора.
Джим Ферранс

Так, я подумав про це після того, як опублікував це. Незалежно від використовуваного методу, замовлення залежить від основної реалізації колекції. Потім "спочатку" стає відносним терміном. Однак ітератор () спосіб це зробити, мабуть, кращий у більшості випадків.
Енді Ґерна

2
Я прийшов сюди, тому що це було рішення, яке я мав, і виявилося некрасивим.
haansn08
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.