Перейти к основному содержимому

Преобразование перечисления Java в поток

· 3 мин. чтения

1. Обзор

Перечисление — это интерфейс из первой версии Java (JDK 1.0). Этот интерфейс является универсальным и обеспечивает ленивый доступ к последовательности элементов . Хотя в более новых версиях Java есть лучшие альтернативы, устаревшие реализации могут по-прежнему возвращать результаты с использованием интерфейса Enumeration . Поэтому для модернизации устаревшей реализации разработчику может потребоваться преобразовать объект Enumeration в Java Stream API .

В этом кратком руководстве мы собираемся реализовать служебный метод для преобразования объектов Enumeration в API Java Stream. В результате мы сможем использовать потоковые методы, такие как filter и map .

2. Интерфейс перечисления Java

Давайте начнем с примера, иллюстрирующего использование объекта Enumeration :

public static <T> void print(Enumeration<T> enumeration) {
while (enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
}

У перечисления есть два основных метода: hasMoreElements и nextElement . Мы должны использовать оба метода вместе, чтобы перебирать коллекцию элементов.

3. Создание разделителя

В качестве первого шага мы создадим конкретный класс для абстрактного класса AbstractSpliterator. Этот класс необходим для адаптации объектов Enumeration к интерфейсу Spliterator :

public class EnumerationSpliterator<T> extends AbstractSpliterator<T> {

private final Enumeration<T> enumeration;

public EnumerationSpliterator(long est, int additionalCharacteristics, Enumeration<T> enumeration) {
super(est, additionalCharacteristics);
this.enumeration = enumeration;
}
}

Помимо создания класса, нам также необходимо создать конструктор. Мы должны передать первые два параметра суперконструктору . Первый параметр — предполагаемый размер Spliterator . Второй предназначен для определения дополнительных характеристик. Наконец, мы будем использовать последний параметр для получения объекта Enumeration .

Нам также необходимо переопределить методы tryAdvance и forEachRemaining . Они будут использоваться Stream API для выполнения действий над элементами Enumeration :

@Override
public boolean tryAdvance(Consumer<? super T> action) {
if (enumeration.hasMoreElements()) {
action.accept(enumeration.nextElement());
return true;
}
return false;
}

@Override
public void forEachRemaining(Consumer<? super T> action) {
while (enumeration.hasMoreElements())
action.accept(enumeration.nextElement());
}

4. Преобразование перечисления в поток

Теперь, используя класс EnumerationSpliterator , мы можем использовать API StreamSupport для выполнения преобразования:

public static <T> Stream<T> convert(Enumeration<T> enumeration) {
EnumerationSpliterator<T> spliterator
= new EnumerationSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED, enumeration);
Stream<T> stream = StreamSupport.stream(spliterator, false);

return stream;
}

В этой реализации нам нужно создать экземпляр класса EnumerationSpliterator . Long.MAX_VALUE — это значение по умолчанию для предполагаемого размера. Spliterator.ORDERED определяет, что поток будет перебирать элементы в порядке, указанном в перечислении.

Далее мы должны вызвать метод потока из класса StreamSupport . Нам нужно передать экземпляр EnumerationSpliterator в качестве первого параметра. Последний параметр определяет, будет ли поток параллельным или последовательным.

5. Тестирование нашей реализации

Тестируя наш метод convert , мы можем заметить, что теперь мы можем создать действительный объект Stream на основе Enumeration :

@Test
public void givenEnumeration_whenConvertedToStream_thenNotNull() {
Vector<Integer> input = new Vector<>(Arrays.asList(1, 2, 3, 4, 5));

Stream<Integer> resultingStream = convert(input.elements());

Assert.assertNotNull(resultingStream);
}

6. Заключение

В этом руководстве мы показали, как преобразовать Enumeration в объект Stream . Исходный код, как всегда, можно найти на GitHub .