我決定在Java中編寫一些通用的高階函數(地圖,過濾器,縮小等),這些類型是通過泛型類型安全的,而且我遇到了通配符匹配問題一個特定的功能。Java泛型 - 實現高階函數,如地圖
只要是完整的,仿函數接口是這樣的:
/**
* The interface containing the method used to map a sequence into another.
* @param <S> The type of the elements in the source sequence.
* @param <R> The type of the elements in the destination sequence.
*/
public interface Transformation<S, R> {
/**
* The method that will be used in map.
* @param sourceObject An element from the source sequence.
* @return The element in the destination sequence.
*/
public R apply(S sourceObject);
}
令人不安的功能就像是一個地圖,但不是轉化集合它把一個地圖(起初我認爲它應該被稱爲mapMap
,但它聽起來很愚蠢,我最終稱它爲remapEntries
)。
我的第一個版本(並採取一坐,因爲簽名是相當的怪物):
/**
* <p>
* Fills a map with the results of applying a mapping function to
* a source map.
* </p>
* Considerations:
* <ul>
* <li>The result map must be non-null, and it's the same object what is returned
* (to allow passing an unnamed new Map as argument).</li>
* <li>If the result map already contained some elements, those won't
* be cleared first.</li>
* <li>If various elements have the same key, only the last entry given the
* source iteration order will be present in the resulting map (it will
* overwrite the previous ones).</li>
* </ul>
*
* @param <SK> Type of the source keys.
* @param <SV> Type of the source values.
* @param <RK> Type of the result keys.
* @param <RV> Type of the result values.
* @param <MapRes>
* @param f The object that will be used to remapEntries.
* @param source The map with the source entries.
* @param result The map where the resulting entries will be put.
* @return the result map, containing the transformed entries.
*/
public static <SK, SV, RK, RV, MapRes extends Map<RK, RV>> MapRes remapEntries(final Transformation<Map.Entry<SK, SV>, Map.Entry<RK,RV>> f, final Map<SK, SV> source, MapRes result) {
for (Map.Entry<SK, SV> entry : source.entrySet()) {
Map.Entry<RK, RV> res = f.apply(entry);
result.put(res.getKey(), res.getValue());
}
return result;
}
而且這似乎是相當正確的,但問題是,所用的轉換必須完全匹配類型參數,使得兼容的類型難以重用map函數。所以我決定通配符添加到簽名,並且它弄成這個樣子:
public static <SK, SV, RK, RV, MapRes extends Map<RK, RV>> MapRes remapEntries(final Transformation<? super Map.Entry<? super SK, ? super SV>, ? extends Map.Entry<? extends RK, ? extends RV>> f, final Map<SK, SV> source, MapRes result) {
for (Map.Entry<SK, SV> entry : source.entrySet()) {
Map.Entry<? extends RK, ? extends RV> res = f.apply(entry);
result.put(res.getKey(), res.getValue());
}
return result;
}
但是,當我試圖對它進行測試,通配符匹配失敗:
@Test
public void testRemapEntries() {
Map<String, Integer> things = new HashMap<String, Integer>();
things.put("1", 1);
things.put("2", 2);
things.put("3", 3);
Transformation<Map.Entry<String, Number>, Map.Entry<Integer, String>> swap = new Transformation<Entry<String, Number>, Entry<Integer, String>>() {
public Entry<Integer, String> apply(Entry<String, Number> sourceObject) {
return new Pair<Integer, String>(sourceObject.getValue().intValue(), sourceObject.getKey()); //this is just a default implementation of a Map.Entry
}
};
Map<Integer, String> expected = new HashMap<Integer, String>();
expected.put(1, "1");
expected.put(2, "2");
expected.put(3, "3");
Map<Integer, String> result = IterUtil.remapEntries(swap, things, new HashMap<Integer, String>());
assertEquals(expected, result);
}
的錯誤是:
method remapEntries in class IterUtil cannot be applied to given types
required: Transformation<? super java.util.Map.Entry<? super SK,? super SV>,? extends java.util.Map.Entry<? extends RK,? extends RV>>,java.util.Map<SK,SV>,MapRes
found: Transformation<java.util.Map.Entry<java.lang.String,java.lang.Number>,java.util.Map.Entry<java.lang.Integer,java.lang.String>>,java.util.Map<java.lang.String,java.lang.Integer>,java.util.HashMap<java.lang.Integer,java.lang.String>
那麼,有關如何解決這個問題的任何提示?或者我應該放棄併爲此寫出明確的循環?^_^
在https://github.com/GlenKPeterson看看/ fp4java7它是Java的高階函數,實現爲對不可變(或可變)集合的惰性轉換。一些持續的懶惰轉換也被實現。這是一個完全通用的界面,儘管在實施過程中有一些演員是合適的。 – GlenPeterson 2014-02-19 16:50:38
呵呵,你遲了3年@GlenPeterson;)btw,加一些測試! :D – fortran 2014-02-20 00:51:30