You can't use those in switches. Switches aren't quite 'a replacement for a bunch of if / else if statements'.
More generally I wouldn't do it this way at all. For many reasons:
- There's an alternative. I think it's pretty good - see below.
- You can't generate a compile-time error if someone calls
convert with a hardcoded data type that you don't support. For example, if you don't have a rule for converting to, say, Boolean, and I write convert(Boolean.class, "true"), it'd be nice if I get an error as I write that line instead of having to wait for the runtime to tell me.
- If you want to convert to a genericsed type, such as: "Please convert this to a
List<Integer>", you can't; Class<?> cannot represent generics. List.class works, List<Integer>.class does not. (There's a hack called 'super type tokens' that sort of can but it's convoluted, wonky syntax, and will confuse readers. I wouldn't go for those lightly!)
- The code is a bit of a mess as it'll have to be a giant
if/elseif block.
- If that list grows long, the code has to walk through every case every time, i.e. it's not very performant.
An alternative:
public final class DataConverters {
private DataConverters() {} // No instantiation
public static final Function<String, Integer> TO_INTEGER = v -> Integer.parse(v);
public static final Function<String, JsonNode> TO_JSON = v -> new ObjectMapper().readTree(v);
// and so on
}
// to use:
String v = readSomeNumber();
int n = DataConverters.TO_INTEGER.apply(v);
If you also need dynamic behaviour, i.e. where some code doesn't know what type is needed and instead the caller to this code tells it what is needed:
public <T> T readFromDb(Db db, String unid, Function<String, T> converter) throws SQLException {
var s = db.select("SELECT data FROM dataTable WHERE unid = ?", unid).singleString();
return converter.apply(s);
}
The above would read data from a database table, and convert it. A caller could for example write: int v = readFromDb(db, "12345", DataConverters.TO_INTEGER);.
Note that you get type safety (these methods return the type you're converting to, not 'Object'), and you can't convert to a type you have no converter for.
If you MUST make it even more dynamic than that, which is a giant code smell and can only be excused if you're interacting with a language with less strict typing rules, you could even do something like this:
// in DataConverters
private static final Map<Class<?>, Function<String, ?>> ALL_CONVERTERS; static {
var m = new HashMap<Class<?>, Function<String, ?>>();
m.put(Integer.class, TO_INTEGER);
// one 'put' call for every converter you wrote.
ALL_CONVERTERS = Collections.unmodifiableMap(m);
}
public static <T> T convert(Class<T> type, String data) {
return type.cast(ALL_CONVERTERS.get(type).apply(data));
}
With that last trick you lose the ability to have converters that convert to genericsed types (you can't have Function<String, List<String>> TO_STRING_LIST = ...;).