在使用新的Java 8 StreamAPI时,我不禁要问,为什么不呢:
public interface Map<K,V> extends Function<K, V>
Run Code Online (Sandbox Code Playgroud)
甚至:
public interface Map<K,V> extends Function<K, V>, Predicate<K>
Run Code Online (Sandbox Code Playgroud)
使用以下default方法实现相当容易Map interface:
@Override default boolean test(K k) {
return containsKey(k);
}
@Override default V apply(K k) {
return get(k);
}
Run Code Online (Sandbox Code Playgroud)
并且它允许Map在map方法中使用a :
final MyMagicMap<String, Integer> map = new MyMagicHashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
map.put("D", 4);
final Stream<String> strings = Arrays.stream(new String[]{"A", "B", "C", "D"});
final Stream<Integer> remapped = strings.map(map);
Run Code Online (Sandbox Code Playgroud)
或者作为Predicate一种filter方法.
我发现a的一小部分用例Map正好是那个构造或类似构造 - 作为重映射/查找Function.
那么,为什么JDK设计者Map在重新设计Java 8时没有决定添加这个功能呢?
Stu*_*rks 14
JDK团队当然知道java.util.Map作为数据结构和java.util.function.Function映射函数之间的数学关系.毕竟,在早期的JDK 8 原型版本中Function命名.并且调用在每个流元素上调用函数的流操作.MapperStream.map
甚至还有一个关于可能重命名Stream.map为其他内容的讨论,例如transform因为转换函数和Map数据结构之间可能存在混淆.(抱歉,找不到链接.)此提案被拒绝,理由是概念上的相似性(map为此目的是常用的).
主要问题是,如果java.util.Map是子类型会得到什么java.util.function.Function?关于子类型是否暗示"is-a"关系的评论中有一些讨论.子类型不是关于对象的"is-a"关系 - 因为我们讨论的是接口而不是类 - 但它确实意味着可替代性.因此,如果Map是子类型Function,则可以执行此操作:
Map<K,V> m = ... ;
source.stream().map(m).collect(...);
Run Code Online (Sandbox Code Playgroud)
我们现在正面临着Function.apply现有Map方法之一的烘焙行为.可能唯一明智的是Map.get,如果密钥不存在则返回null.坦率地说,这些语义有点糟糕.真正的应用程序可能必须编写自己的方法来提供密钥丢失策略,所以似乎没有什么优势可以编写
map(m)
Run Code Online (Sandbox Code Playgroud)
代替
map(m::get)
Run Code Online (Sandbox Code Playgroud)
要么
map(x -> m.getOrDefault(x, def))
Run Code Online (Sandbox Code Playgroud)
问题是"为什么要扩展Function?"
你使用的例子strings.map(map)并没有真正证明改变类型继承的想法(暗示为Map接口添加方法),因为它没有什么区别strings.map(map::get).而且目前尚不清楚是否一个使用Map的Function是真的常见的,它应该比获得特殊待遇,例如使用map::remove一个Function或使用map::get一个的Map<…,Integer>作为ToIntFunction或map::get的Map<T,T>作为BinaryOperator.
在a的情况下,这更令人质疑Predicate; map::containsKey真的应该得到一个特殊的待遇比较map::containsValue?
值得注意的是方法的类型签名.Map.get有一个功能签名Object ? V虽然你建议Map<K,V>应该扩展Function<K,V>,这可以从地图的概念视图(或只是通过查看类型)可以理解,但它表明有两个相互矛盾的期望,取决于你是否看到方法或在类型.最好的解决方案是不修复功能类型.然后你可以分配map::get给任何一个Function<Object,V>或者Function<K,V>每个人都很高兴...
因为 Map 不是函数。继承是针对A 是 B 的关系。Not for A 可以成为各种 B关系的主题。
要将键转换为其值的函数,您只需要
Function<K, V> f = map::get;
Run Code Online (Sandbox Code Playgroud)
要进行谓词测试对象是否包含在地图中,您只需要
Predicate<Object> p = map::contains;
Run Code Online (Sandbox Code Playgroud)
这比您的提案更清晰、更易读。
| 归档时间: |
|
| 查看次数: |
400 次 |
| 最近记录: |