построение универсальной функции инициализатора в Java - PullRequest
3 голосов
/ 15 августа 2011

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

Следует использовать так:

Integer myVar = ConversionHelper.initialize( "123", 0 ) // should return Integer(123)
Integer myVar = ConversionHelper.initialize( "hello", 0 ) // should return Integer(0)

и т. Д.

Я попробовал следующий код:

public static <T> T initialize(Object o, T def) {
    T ret;

    try {
        ret = (T) o;
    } catch (Exception e) {
        ret = def;
    }

    return ret==null ? def : ret;
}

но это не удается при базовых преобразованиях, таких как приведение целого числа к строке.

РЕДАКТИРОВАТЬ: взял много предложений из ответов, и теперь я ищу способ сделать это без серии if .. elseif ... elseif и блока try catch, который появляется в моем ответе

Ответы [ 4 ]

3 голосов
/ 15 августа 2011

Это то, что вы ищете:

public static <T> T initialize(Object o, T def) {

    if ( o == null ) return def;

    if ( def == null ) throw new NullPointerException("Null def");

    if ( !def.getClass().isAssignableFrom(o.getClass()) ) {
        return def;
    } else {
        return (T) o;
    }

}

Однако вы не можете использовать его на примитивных типах, как вы упоминаете в своем вопросе.Чтобы использовать этот метод, вам необходимо объединить их в объекты.

РЕДАКТИРОВАТЬ

Если null является допустимым параметром, то:

public static <T> T initialize(Object o, T def) {

    if ( o == null ) return def;

    if ( def == null ) null;

    if ( !def.getClass().isAssignableFrom(o.getClass()) ) {
        return def;
    } else {
        return (T) o;
    }

}

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

2 голосов
/ 15 августа 2011
public static <T> T initialize(Object o, T def) {
    T ret;

    try {
        ret = def.getClass().cast(o);
    } catch (Exception e) {
        ret = def;
    }

    return ret==null ? def : ret;
}
2 голосов
/ 15 августа 2011

Подстановочные знаки действительны только как тип параметры , а не как типы.В этом случае, как вы заметили, старый Object так же хорош.

Другой действительной подписью будет:

public static <IN, OUT> OUT initialize(IN o, OUT default) { ... }

Но в вашем случае это выглядит ненужным, посколькууниверсальные типы не ограничены.

Что касается вашей стратегии конверсии с использованием приведения в пределах try / catch, я не уверен в этом.Кто-то должен взвесить эту часть.

РЕДАКТИРОВАТЬ: как вы обнаружили, приведение очень ограничено, когда речь идет о всех, кроме самых простых преобразований данных.Возможно, вам потребуется реализовать сопоставления с соответствующими вызовами методов синтаксического анализа в зависимости от типов ввода и вывода.

EDIT2: в качестве примера того, с чем вы сталкиваетесь, вот метод преобразования данныхкто-то написал для проекта, в котором я сейчас участвую:

public static <T> T mapValueString(String valueString, Class<T> targetType) {

  if (valueString == null) {
     return null;
  }
  else if(targetType.equals(String.class)) {
     return (T)valueString;
  }
  else if (targetType.equals(Date.class)) {
     return (T)MyDateTime.parseDate(valueString);
  }
  else if (targetType.equals(Timestamp.class)) {
     return (T)MyDateTime.parseTimestamp(valueString);
  }
  else if (targetType.equals(Boolean.class)) {
     String upperVal = valueString.toUpperCase();
     if (upperVal.startsWith("T")) {
        return (T)Boolean.TRUE;
     }
     else if (upperVal.startsWith("F")) {
        return (T)Boolean.FALSE;
     }
     else {
        throw new RuntimeException("Failed to parse value string into Boolean object. String was " + valueString + ".");
     }
  }
  else if (targetType.equals(Integer.class)) {
     Integer i;
     try {
        i = Integer.parseInt(valueString);
     }
     catch (NumberFormatException nfe) {
        throw new RuntimeException("Failed to parse value string into Integer object. String was " + valueString + ".", nfe);
     }
     return (T)i;
  }
  else if (targetType.equals(Long.class)) {
    Long l;
    try {
       l = Long.parseLong(valueString);
    }
    catch (NumberFormatException nfe) {
       throw new RuntimeException("Failed to parse value string into Long object. String was " + valueString + ".", nfe);
    }
    return (T)l;
  }
  else if (targetType.equals(Double.class)) {
     Double d;
     try {
        d = Double.parseDouble(valueString);
     }
     catch (NumberFormatException nfe) {
        throw new RuntimeException("Failed to parse value string into Double object. String was " + valueString + ".", nfe);
     }
     return (T)d;
  }
  else {
     throw new RuntimeException("Unsupported java type " + targetType.getName() + ".");
  }
}

Обратите внимание, что это только для отображения String в T, где вы хотите отобразить T1 в T2.Есть ли способ лучше?Может быть.Может ли ТА помочь вам найти правильную стратегию?Конечно, но мяч на вашей площадке, чтобы задавать правильные вопросы.

EDIT3: Apache Commons 'beanutils.converters может помочь.Я не пробовал это, хотя, поэтому я не могу отметить это.

0 голосов
/ 15 августа 2011

Большое спасибо за все ответы, но я столкнулся со следующей проблемой

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

, поэтому я придумал следующее

public static <T> T initialize(Object o, T def) {

    if (o==null) return def;

    try {
        if (def.getClass().isAssignableFrom(String.class)) {
            return (T) o.toString();
        } else if (def.getClass().isAssignableFrom(Integer.class)) {
                return (T) Integer.valueOf(o.toString());
        } else if (def.getClass().isAssignableFrom(Long.class)) {
            return (T) Long.valueOf(o.toString());
        } else if (def.getClass().isAssignableFrom(o.getClass())) {
            return (T) o;
        } else {
            return def;
        }
    } catch (Exception e) {
        return def;
    }
}

, и я думаю, что яМне просто нужно добавить еще несколько файлов по пути ...

о, и это тест, который я проходил до сих пор ...

    assertEquals("trivial case, should return the value passed",
            "hello",
            initialize("hello", "default salutation"));

    assertEquals("should return the default value",
            "default salutation",
            initialize(null, "default salutation"));

    assertEquals("should convert to the default value type",
            "123",
            initialize(123, "0"));

    assertEquals("should convert to the default value type",
            (Long) 10L, 
            initialize("10", 0L));

    assertEquals("should return default value if it can't convert to the default value type",
            (Long) 0L,
            initialize("hola", 0L));

любая лучшая альтернатива ??

...