Я пытаюсь найти способ выполнить итерации через значения перечисления при использовании дженериков. Не уверенный, как сделать это или если это возможно.
Следующий код иллюстрирует то, что я хочу сделать. Обратите внимание, что код 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);
}
}
}
Какие-либо идеи, как сделать это, не нуждаясь в дополнительном параметре Класса в конструкторах?
Это действительно сложная проблема. Одна из вещей, которые вам нужно сделать, - это сообщить java, что вы используете перечисление. Это означает, что вы расширяете класс Enum для своих дженериков. Однако в этом классе нет функции values (). Итак, вы должны выбрать класс, для которого вы можете получить значения.
Следующий пример поможет вам решить вашу проблему:
public <T extends Enum<T>> void enumValues(Class<T> enumType) {
for (T c : enumType.getEnumConstants()) {
System.out.println(c.name());
}
}
Использование небезопасного преобразования:
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);
}
}
}
Другой вариант - использовать 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);
}
}
Если вы уверены, что 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);
}
}
}
Надеюсь, это поможет.
Следует повторно создать исключение как пользовательское исключение во время выполнения, а не универсальное исключение, например Исключение BadRuntiveException
. Также можно попробовать туннелирование исключений .
И я уверен, что заставлять клиентов справляться с исключениями, заставляя их проверять, - плохая практика. Это просто загрязняет ваш код или заставляет переносить исключения в среду выполнения или заставлять обрабатывать их в месте вызова, но не централизованно. Моя политика заключается в том, чтобы максимально избегать использования проверенных исключений. Рассмотрим IOException
на Closable.close ()
: полезно или удобно? Случаи, когда это большая редкость, но каждый разработчик Java в мире вынужден им заниматься. Чаще всего его глотают или регистрируют в лучшем случае. И представьте, насколько это увеличивает размер кода !
Есть некоторые сообщения о проверенных исключениях с их темной стороны:
Там Но на мой взгляд они редки и обычно касаются реализации какого-то конкретного модуля. И они не дают большой прибыли.
-121--1364212-Я ограничил доступ к файлам, связавшись со скриптом php, который проверяет, имеет ли пользователь доступ к файлу, и повторяет файл с помощью readfile () , если у пользователя есть доступ к файлу. Затем файл можно сохранить в каталоге, доступ к которому невозможен непосредственно по URL-адресу.
-121--1930390-Корневая проблема заключается в том, что необходимо преобразовать массив в список, верно? Это можно сделать, используя определенный тип (TimePeriod вместо T) и следующий код.
Поэтому используйте следующее:
List<TimePeriod> list = new ArrayList<TimePeriod>();
list.addAll(Arrays.asList(sizes));
Теперь вы можете передать список любому методу, который хочет список.
Если вы объявите 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());
}
}
}