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 .