任意のコレクションを取得し、それをNumber(Long、Double、Float、Integerなど)から拡張するユーザー選択可能なクラスのコレクションに変換する非常に汎用的なユーティリティメソッドを作成したい
私は、Googleコレクションを使用してコレクションを変換し、不変リストを返すこのコードを思いつきました。
import java.util.List;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
/**
* Takes a {@code List<String>} and transforms it into a list of the
* specified {@code clazz}.
*
* @param <T>
* @param stringValues
* the list of Strings to be used to create the list of the
* specified type
* @param clazz
* must be a subclass of Number. Defines the type of the new List
* @return
*/
public static <T extends Number> List<T> toNumberList(List<String> stringValues, final Class<T> clazz) {
List<T> ids = Lists.transform(stringValues, new Function<String, T>() {
@SuppressWarnings("unchecked")
@Override
public T apply(String from) {
T retVal = null;
if (clazz.equals(Integer.class)) {
retVal = (T) Integer.valueOf(from);
} else if (clazz.equals(Long.class)) {
retVal = (T) Long.valueOf(from);
} else if (clazz.equals(Float.class)) {
retVal = (T) Float.valueOf(from);
} else if (clazz.equals(Double.class)) {
retVal = (T) Double.valueOf(from);
} else {
throw new RuntimeException(String.format("Type %s is not supported (yet)", clazz.getName()));
}
return retVal;
}
});
return ImmutableList.copyOf(ids);
}
次のように使用できます。
// Convert List<String> to List<Long>
List<Long> ids = MiscUtils.toNumberList(productIds, Long.class);
私のコードはやりすぎですか、それともどのように単純化し、同時に十分に汎用性を維持しますか?
このコードの最も重要な側面はFunction
、メソッド自体とは対照的にです。また、が作成されたときにFunction
どのタイプのNumber
戻り値を返したいのかすでにわかっているので、本文で許可するサブクラスを切り替えることは意味がないと思いますFunction
。たとえば、が指定された場合にメソッドが失敗することも、少し問題がありますBigInteger.class
。
これを踏まえて、私が行うことは、ユーティリティクラスを作成し(それをNumbers
と呼びましょう)、それぞれをを特定のタイプとして解析するためにFunction
(enum
シングルトンにすることができる)を返すメソッドを提供することString
ですNumber
。あれは:
public class Numbers {
public static Function<String, Integer> parseIntegerFunction() { ... }
public static Function<String, Long> parseLongFunction() { ... }
...
}
それらはそれぞれ次のようなものを実装することができます:
public static Function<String, Integer> parseIntegerFunction() {
return ParseIntegerFunction.INSTANCE;
}
private enum ParseIntegerFunction implements Function<String, Integer> {
INSTANCE;
public Integer apply(String input) {
return Integer.valueOf(input);
}
@Override public String toString() {
return "ParseIntegerFunction";
}
}
これは、ユーザーが望む方法で使用できます。
List<String> strings = ...
List<Integer> integers = Lists.transform(strings, Numbers.parseIntegerFunction());
このアプローチには、いくつかの利点があります。
Function
...での切り替えは必要ありません。作成する数値のタイプはわかっているので、それを実行します。もっと早く。Function
どこでも使用できます...ユーザーはメソッドのように使用する必要がありません(変換された値をにコピーします)ImmutableList
。Function
実際に許可したいs のみを作成します。BigInteger
解析関数がない場合、ユーザーはそれを呼び出すことができません。これは、例のようにコンパイル時にそれを実行し、実行時に失敗することを完全に正当にすることとは対照的です。補足として、ImmutableList
be ImmutableList
ではなくbe を返すメソッドの戻り値の型を作成することをお勧めしますList
。これは、メソッドのクライアントに役立つ情報を提供します。
編集:
より動的なものが本当に必要な場合(つまり、sをその型Class<T extends Number>
に変換できるようにいくつかのインスタンスを持つクラスが必要な場合)、次のようなlookupメソッドを追加することもできます。String
Number
public static <T extends Number> Function<String, T> parseFunctionFor(Class<T> type) {
// lookup the function for the type in an ImmutableMap and return it
}
ただし、Number
提供しないサブクラスがある場合、これには元のメソッドと同じ問題がありますFunction
。また、これが役立つ多くの状況があるようにも思われません。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加