我发现在使用java集合时,特别是在使用泛型编写实用程序方法时,我的代码通常又丑又臃肿,充满了空检查,嵌套循环和重复。 专注于这个例子,我想要改进的想法。
假设我们有一个EnumMap
,其值是评级列表。 例如,假设enum
本身表示水果,每个值表示由不同人员给出的列表评级。
APPLE -> [1, 3, 4]
ORANGE -> [2, 0, 5]
John rated apple 1, Mary rated apple 3, Steve rated apple 4
John rated orange 2, Mary rated orange 0, Steve rated orange 5
Note the specific names are irrelevant and provided only to clarify the setup
现在我们要编写一个实用方法,该方法接受类似于上面的数据结构,并返回每个人最喜欢的水果的列表。 因此,上述样本数据的预期结果将是:自2 > 1
以来[ORANGE, APPLE, ORANGE
、3 > 0
和5 > 4
。
以下是我目前执行此操作的方法。 我想要一种同样(或更(高效但更干净的方法来编写相同的算法。
谢谢!
public class MyListUtil {
public static <K extends Enum<K>, T extends Object & Comparable<? super T>> List<K> maxKeysByIndex(EnumMap<K, List<T>> enumMap) {
Iterator<K> keysIter = enumMap.keySet().iterator();
int sizeOfAllLists = enumMap.get(keysIter.next()).size();
List<K> ret = new ArrayList<K>();
for (int i=0; i<sizeOfAllLists; i++) {
keysIter = enumMap.keySet().iterator();
K maxIndexKey = null;
T maxIndexVal = null;
while (keysIter.hasNext()){
K curKey = keysIter.next();
T curVal = enumMap.get(curKey).get(i);
if (maxIndexVal == null || curVal.compareTo(maxIndexVal) > 0) {
maxIndexVal = curVal;
maxIndexKey = curKey;
}
}
ret.add(maxIndexKey);
}
return ret;
}
}
真的很丑。
IMO 在这里使用枚举是错误的。枚举应该是编程常量,而不是人们的偏好。
您应该创建一个类 PersonFruitPpreferences,该类使用地图来允许 Person 设置水果首选项。同时添加一个方法 getFavoriteFruit((
如果您需要很多都对相同泛型类型进行操作的方法,我认为您可以将用于 K
和 T
的辅助方法放入一个类中,然后只指定整个类的完整泛型类型。 要使用它们,您需要创建该类的对象,然后从中调用方法。
该对象将是无状态的,但它为您提供了一种将所有详细内容放在一个位置的语法方法。
public class <K extends Enum<K>, T extends Object & Comparable<? super T>> MyListUtil {
public List<K> maxKeysByIndex(EnumMap<K, List<T>> enumMap) {
...
//other methods
}
您可以尝试将内部循环放入单独的方法中,例如:
public K getMaxKeyFromPos(EnumMap<K, List<T>> enumMap, int pos)
{
K maxIndexKey = null;
T maxIndexVal = null;
for (K curKey : enumMap.keySet()) {
T curVal = enumMap.get(curKey).get(pos);
if (maxIndexVal == null || curVal.compareTo(maxIndexVal) > 0) {
maxIndexVal = curVal;
maxIndexKey = curKey;
}
}
return maxIndexKey;
}
我还将其更改为for-each
语法,删除了一些迭代器。
首次使用排序列表。
第二个简单调用:
列表结果;for(T in enummap( { result.add(enummap.get(t(.get(0((;假设您执行了降序排序}
返回结果。
宣传 Scala 的绝佳机会。您可能知道,Scala运行在JVM上,并且与Java字节码完全兼容。它自己被编译成JVM字节码。
从这个精益的工作代码中看不出什么:
val apple = List (1, 3, 4)
val orange = List (2, 0, 5)
val persons = List ("John", "Mary", "Steve")
val prefs = apple.zip (orange) .zip (persons)
// List[((Int, Int), java.lang.String)] = List(((1,2),John), ((3,0),Mary), ((4,5),Steve))
prefs.map (e => e._2 + ": " + (if (e._1._1 > e._1._2) "apple" else "orange"))
// List[java.lang.String] = List(John: orange, Mary: apple, Steve: orange)
是,您具有完全的静态编译时安全性。但是在可能的情况下会推断出类型,因此您的样板要少得多。
前 3 行生成 3 个列表。然后它们被压缩 - 在你看到的评论中,类型推断者说他发现了什么。
这部分有点晦涩难懂:
(e => e._2 + ": " + (if (e._1._1
Prefs 是 List of ((Pair of Int(, String(,e 是列表中的一个元素。 e._2是字符串部分(出于某种原因,在这样的元组中,我们不是从 0 开始计数,而是从 1 开始计数 - 我猜,因为元组起源的地方,有这种习惯(,而列表和数组等也从 0 开始计数, 比如爪哇。
e._1是元素的第一部分,一对 Int,它们是水果的偏好。 第一个水果为 e._1._1,第二个水果为 e._1._2。
在使用 Scala 集合一段时间后,我不再喜欢 Java了。 :)但当然,并非每家公司都允许改变,学习需要一段时间。