Java: не отмечал отбрасывание от X на Y / Как реализовать Cacornull

StackOverflow https://stackoverflow.com/questions/3933609

Вопрос

Я реализовал эту функцию:

 static <X,Y> Y castOrNull(X obj) {
  try {
   return (Y)obj;
  }
  catch(ClassCastException e) {
   return null;
  }
 }

Это дает мне компилятор предупреждение:

Type safety: Unchecked cast from X to Y

Который я не точно понимаю. Не то try/catch Что я здесь делаю здесь чеком? Могу ли я игнорировать предупреждение?

Будет ли моя функция работать как ожидалось или нет? Как бы я правильно осуществил?

Я также пробовал с obj instanceof Y Проверьте, но это не работает из-за того, как Java обрабатывает универсальные дженерики.

BTW. Эта функция кажется мне довольно полезной (чтобы сделать какой-то другой код более чистой). Интересно, может ли такая функция уже существовать в Java?


Одним из примеров, где я хочу использовать это:

    void removeEmptyRawStrings() {
        for(Iterator<Entity> e = entities.iterator(); e.hasNext();) {
            RawString s = castOrNull(e.next());
            if(s != null && s.content.isEmpty()) e.remove();
        }
    }

У меня такие случаи, как это довольно часто в моем коде. И я думаю, что это более читаемое и проще, чем что-либо еще. Но, пожалуйста, дайте мне лучшее предложение, если у вас есть какие-либо о том, как сделать этот код еще проще.

Это было полезно?

Решение

Так что проблема здесь в том, что общий параметр Y При использовании для динамического литья обрабатывается как Object. Отказ Это никогда не бросит CCE. Вы получаете CCE, брошенный в призыв Способ, поскольку вы сломали статический тип безопасности.

Также X здесь совершенно бессмысленно:

Почти наверняка правильное решение не пытается ничего подобного. null плохо. Кастинг плохой.

Однако, если вы решите написать ерунду, вы можете пройти Class объект:

public static <T> T evilMethod(Class<T> clazz, Object obj) {
    try {
        return clazz.cast(obj);
    } catch (ClassCastException exc) {
        return null;
    }
}

Другие советы

Я не совсем уверен, что это будет работать должным образом. (Зависит от того, что вы ожидаете, конечно, :-) Но этот код например, приведет к java.lang.ClassCastException (Идеон):

public class Main {

    public static void main(String[] args) {
        Integer o = Main.<String, Integer>castOrNull("hello");
    }


    public static <X, Y> Y castOrNull(X obj) {
        try {
            return (Y) obj;
        } catch (ClassCastException e) {
            return null;
        }
    }
}

@ Том Хонтин получил «правильное» решение.

Вы можете подавить предупреждение в этом методе, если вы точно знаете, что это не проблема, аннотируя его @SuppressWarnings("unchecked")

Благодаря тому, как Java Generics, где спроектирован этот код вообще не будет работать. Generics полезны только для проверки типа компиляции, поскольку классы не используют информацию об общем типе во время выполнения.

Ваш код будет скомпилирован к этому:

 static Object castOrNull(Object obj) {
  try {
   return (Object)obj;//FAIL: this wont do anything
  }
  catch(ClassCastException e) {
   return null;
  }
 }

Лицовой объект никогда не потерпит неудачу, и скомпилированным кодом не имеет доступа к общим типом, присутствующим в компиляционном времени. Поскольку отказ не произошел так, как следует получить предупреждение для неконкуренной операции.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top