如何改进使用 java 泛型编写的实用程序算法的设计和可读性



我发现在使用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, ORANGE3 > 05 > 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((

如果您需要很多都对相同泛型类型进行操作的方法,我认为您可以将用于 KT 的辅助方法放入一个类中,然后只指定整个类的完整泛型类型。 要使用它们,您需要创建该类的对象,然后从中调用方法。

该对象将是无状态的,但它为您提供了一种将所有详细内容放在一个位置的语法方法。

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了。 :)但当然,并非每家公司都允许改变,学习需要一段时间。

最新更新