Выполните итерации перечислимых значений с помощью дженериков Java

Я пытаюсь найти способ выполнить итерации через значения перечисления при использовании дженериков. Не уверенный, как сделать это или если это возможно.

Следующий код иллюстрирует то, что я хочу сделать. Обратите внимание, что код T.values () не действителен в следующем коде.

public class Filter<T> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        this.selectedOption = selectedOption;
        for (T option : T.values()) {  // INVALID CODE
            availableOptions.add(option);
        }
    }
}

Вот то, как я инстанцировал бы Объекта фильтра:

Filter<TimePeriod> filter = new Filter<TimePeriod>(TimePeriod.ALL);

Перечисление определяется следующим образом:

public enum TimePeriod {
    ALL("All"), 
    FUTURE("Future"), 
    NEXT7DAYS("Next 7 Days"), 
    NEXT14DAYS("Next 14 Days"), 
    NEXT30DAYS("Next 30 Days"), 
    PAST("Past"),
    LAST7DAYS("Last 7 Days"), 
    LAST14DAYS("Last 14 Days"),
    LAST30DAYS("Last 30 Days"); 

    private final String name;

    private TimePeriod(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}

Я понимаю, что не могло бы иметь смысла копировать значения перечисления в список, но я пользуюсь библиотекой, которая нуждается в списке значений, как введено и не будет работать с перечислениями.


РЕДАКТИРОВАНИЕ 05.02.2010:

Большинство предложенных ответов очень похоже и предлагает делать что-то вроде этого:

class Filter<T extends Enum<T>> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        Class<T> clazz = (Class<T>) selectedOption.getClass();
        for (T option : clazz.getEnumConstants()) {
            availableOptions.add(option);
        }
    }
}

Это работало бы отлично, если я могу быть уверен, что selectedOption имеет ненулевое значение. К сожалению, в моем варианте использования, это значение является часто нулевым, поскольку существует общедоступный Фильтр () конструктор без аргументов также. Это означает, что я не могу сделать selectedOption.getClass (), не получая NPE. Этот класс фильтра управляет списком доступных вариантов, который из опций выбран. Когда ничто не выбрано, selectedOption является пустым.

Единственная вещь я могу думать для решения этого, состоит в том, чтобы на самом деле передать в Классе в конструкторе. Так что-то вроде этого:

class Filter<T extends Enum<T>> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(Class<T> clazz) {
        this(clazz,null);
    }

    public Filter(Class<T> clazz, T selectedOption) {
        this.selectedOption = selectedOption;
        for (T option : clazz.getEnumConstants()) {
            availableOptions.add(option);
        }
    }
}

Какие-либо идеи, как сделать это, не нуждаясь в дополнительном параметре Класса в конструкторах?

66
задан Tauren 5 February 2010 в 22:26
поделиться

6 ответов

Это действительно сложная проблема. Одна из вещей, которые вам нужно сделать, - это сообщить java, что вы используете перечисление. Это означает, что вы расширяете класс Enum для своих дженериков. Однако в этом классе нет функции values ​​(). Итак, вы должны выбрать класс, для которого вы можете получить значения.

Следующий пример поможет вам решить вашу проблему:

public <T extends Enum<T>> void enumValues(Class<T> enumType) {
        for (T c : enumType.getEnumConstants()) {
             System.out.println(c.name());
        }
}
107
ответ дан 24 November 2019 в 14:59
поделиться

Использование небезопасного преобразования:

class Filter<T extends Enum<T>> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        Class<T> clazz = (Class<T>) selectedOption.getClass();
        for (T option : clazz.getEnumConstants()) {
            availableOptions.add(option);
        }
    }
}
4
ответ дан 24 November 2019 в 14:59
поделиться

Другой вариант - использовать EnumSet:

class PrintEnumConsants {

    static <E extends Enum <E>> void foo(Class<E> elemType) {
        for (E e : java.util.EnumSet.allOf(elemType)) {
            System.out.println(e);
        }
    }

    enum Color{RED,YELLOW,BLUE};
    public static void main(String[] args) {
        foo(Color.class);
    } 

}
11
ответ дан 24 November 2019 в 14:59
поделиться

Если вы уверены, что selectedOption конструктора Filter (T selectedOption) не имеет значения NULL. Вы можете использовать отражение. Как это.

public class Filter<T> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        this.selectedOption = selectedOption;
        for (T option : this.selectedOption.getClass().getEnumConstants()) {  // INVALID CODE
            availableOptions.add(option);
        }
    }
}

Надеюсь, это поможет.

1
ответ дан 24 November 2019 в 14:59
поделиться

Следует повторно создать исключение как пользовательское исключение во время выполнения, а не универсальное исключение, например Исключение BadRuntiveException . Также можно попробовать туннелирование исключений .

И я уверен, что заставлять клиентов справляться с исключениями, заставляя их проверять, - плохая практика. Это просто загрязняет ваш код или заставляет переносить исключения в среду выполнения или заставлять обрабатывать их в месте вызова, но не централизованно. Моя политика заключается в том, чтобы максимально избегать использования проверенных исключений. Рассмотрим IOException на Closable.close () : полезно или удобно? Случаи, когда это большая редкость, но каждый разработчик Java в мире вынужден им заниматься. Чаще всего его глотают или регистрируют в лучшем случае. И представьте, насколько это увеличивает размер кода ! Есть некоторые сообщения о проверенных исключениях с их темной стороны:

  1. «Нужны ли проверенные исключения Java?» Брюса Экеля
  2. Проблемы с проверенными исключениями Разговор с Андерсом Гейльсбергом, Билл Веннерс с Брюсом Экелем
  3. Недостатки дизайна Java, C2 wiki

Там Но на мой взгляд они редки и обычно касаются реализации какого-то конкретного модуля. И они не дают большой прибыли.

-121--1364212-

Я ограничил доступ к файлам, связавшись со скриптом php, который проверяет, имеет ли пользователь доступ к файлу, и повторяет файл с помощью readfile () , если у пользователя есть доступ к файлу. Затем файл можно сохранить в каталоге, доступ к которому невозможен непосредственно по URL-адресу.

-121--1930390-

Корневая проблема заключается в том, что необходимо преобразовать массив в список, верно? Это можно сделать, используя определенный тип (TimePeriod вместо T) и следующий код.

Поэтому используйте следующее:

List<TimePeriod> list = new ArrayList<TimePeriod>();
list.addAll(Arrays.asList(sizes));

Теперь вы можете передать список любому методу, который хочет список.

0
ответ дан 24 November 2019 в 14:59
поделиться

Если вы объявите Filter как

public class Filter<T extends Iterable>

, то

import java.util.Iterator;

public enum TimePeriod implements Iterable {
    ALL("All"),
    FUTURE("Future"),
    NEXT7DAYS("Next 7 Days"),
    NEXT14DAYS("Next 14 Days"),
    NEXT30DAYS("Next 30 Days"),
    PAST("Past"),
    LAST7DAYS("Last 7 Days"),
    LAST14DAYS("Last 14 Days"),
    LAST30DAYS("Last 30 Days");

    private final String name;

    private TimePeriod(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }

    public Iterator<TimePeriod> iterator() {
        return new Iterator<TimePeriod>() {

            private int index;

            @Override
            public boolean hasNext() {
                return index < LAST30DAYS.ordinal();
            }

            @Override
            public TimePeriod next() {
                switch(index++) {
                    case    0   : return        ALL;
                    case    1   : return        FUTURE;
                    case    2   : return        NEXT7DAYS;
                    case    3   : return        NEXT14DAYS;
                    case    4   : return        NEXT30DAYS;
                    case    5   : return        PAST;
                    case    6   : return        LAST7DAYS;
                    case    7   : return        LAST14DAYS;
                    case    8   : return        LAST30DAYS;
                    default: throw new IllegalStateException();
                }
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}

И использовать довольно просто:

public class Filter<T> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        this.selectedOption = selectedOption;
        Iterator<TimePeriod> it = selectedOption.iterator();
        while(it.hasNext()) {
            availableOptions.add(it.next());
        }
    }
}
0
ответ дан 24 November 2019 в 14:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: