如何实现List,Set和Map在零免费设计?(How to implement List, Set

2019-09-17 11:27发布

它的伟大时,你可以返回一个空在大多数情况下/空的对象,避免空值,但对于喜欢收藏的对象?

在Java中, Map返回null ,如果keyget(key)在地图上是找不到的。

我能想到的,以避免的最佳方式null在这种情况下s是返回一个Entry<T>对象,它要么是EmptyEntry<T>或者包含值T

当然,我们避免了null ,但现在你可以有一个类转换异常,如果你不检查,如果它的EmptyEntry<T>

有没有更好的方法,以避免null以s Mapget(K)

而对于争论的缘故,让我们说这种语言甚至没有null ,所以不要说只是使用nulls

Answer 1:

两种可能的解决方案:

  1. 提供一个包含(Key)的功能。 如果GET(键)称作一个不存在的键抛出异常。 其缺点是:调用get()后,包含()复制操作; 效率不高。

  2. 函数式语言在类似情况下可能使用。 本文介绍了如何用Java实现可能 。



Answer 2:

你可以抛出一个“元素不存在excepton”,但例外的是昂贵的,并应保留“特殊情况”。 不存在于地图的值是很难的情况下,所以它可能是一个减速带,但像往常一样,这取决于你是在上下文。

无论哪种方式,作为一个建议,你应该考虑使用含有(key)方法。 总有那么键被映射到空值posiblity,所以得到(键)将返回null,出现在你的地图即使!!!

编辑:

看的get()的源代码后,我想出了(备案:完全未经测试,这里当前时间是上午01点08分,我有一个可怕的寒冷!)

  314       public V get(Object key) {
  315           if (key == null)
  316               return getForNullKey();
  317           int hash = hash(key.hashCode());
  318           for (Entry<K,V> e = table[indexFor(hash, table.length)];
  319                e != null;
  320                e = e.next) {
  321               Object k;
  322               if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
  323                   return e.value;
  324           }
                //This could be instanced by reflection (bad idea?)
  325           return new MappeableElementImpl();
   }

我你可能迫使V至实施为MappeableElement一些接口,或者类似的东西其中有一个方法布尔isUnmappedValue(),那么get()方法可以返回该接口的一个实例。

所以它会在像结束:

Element e = map.get(notpresentkey);

if (e.isUnmappedValue()){sysout (notpresentkey  +" is not present");}


Answer 3:

是你的问题所造成的一些不寻常的要求或情况为你设计的数据结构,或者你只是theoreticizing? 如果是后者,你可能要考虑的是,空是从任何其他参考值(例如参考一些最终OBJ表示空)概念上没有区别,和异常昂贵。 除非你有特别的关注或目标让你问这个问题,你真的浪费(Y),我们的时间。 干杯!



Answer 4:

返回一个通用的实例Optional<T>类型。



Answer 5:

有三种可能性,因为我看到它。

  • 返回一个null或空对象。
  • 抛出和捕获异常。
  • 或致电避免问题containsKey打电话之前get

如果你担心的空对象是错误的类型,那么你可以设计自己的地图接受NullObjectFactory,对于你和什么打交道(如创建正确类型的特殊Null对象空对象模式 ) 。 这样,你可以get从一个地图,而无需检查它是否包含密钥,无需检查,如果它返回一个null ,而不必捕获任何异常。



Answer 6:

抛出异常。 这方面的例子是.NET的KeyNotFoundException ,Java的ArrayIndexOutOfBoundsException ,和Python的KeyError

正如我们都知道的例外是特殊情况,所以用户应该预计到检查的一个关键看它之前就存在。

if collection.contains(key):
    return collection.get(key);

try:
    return collection.get(key);
catch KeyError:
    pass # Don't care.


Answer 7:

参看 @Doug麦克林以上-这听起来像斯卡拉调用Option和Haskell调用Maybe 。 这是一个很多像你所描述的,与EntryEmptyEntry -斯卡拉使用Some为有效Entry S和NoneEmptyEntry

丹尼尔Spiewak有一个很好的介绍来Option ,包括基本的Java实现。 (相反,他instanceof None检查,不过,我想可能有一个isNone()方法,也许只是一个None实例-因为Java泛型在运行时被擦除,它从来没有真正包含什么,你可以施放它,或有蒙上它,到任何一个“工厂”的方法None<T>需要。)



Answer 8:

我想你可以返回一个有一个布尔对于找到的对象并拥有或者找到的项目或抛出一个异常的项目。 另一种方法是使用TryGet技术。



Answer 9:

据我所知,你正在寻找一个替代空,但替代品似乎都导致一些异常的情况下,这是更为昂贵(生成踪迹,等)比对测试空。

因此,为了保持在游戏中,返回InvalidValueException试图插入一个无效的(即空)值,或在糟返回NoValuePresentException时()。 (所有的,而希望有一个简单的空测试,你可以执行)



Answer 10:

概念上,它是一个大问题。 其中一个有用的方案是创建适配器,它代表所有呼叫到底层的地图对象。 对于这个适配器会出现要求其指定的参数null对象。 例如:

class MapAdapter<K,V> implements Map<K,V> {
    private Map<K,V> inner = new HashMap<K,V>();
    private final V nullObject;

    private MapAdapter(V nullObject) {
        this.nullObject = nullObject;
    }

    public static <K,V> Map<K,V> adapt(Map<K,V> mapToAdapt, V nullObject) {
        MapAdapter<K,V> adapter = new MapAdapter<K,V>(nullObject);
        adapter.inner.addAll(mapToAdapt);
        return adapter;
    }


    //Here comes implementation of methods delegating to inner.


   public V get(K key) {
       if (inner.containsKey(key)) {
           return inner.get(key);
       }
       return nullObject;
   }
}

大量的工作,但它允许通用NullSafe实现。



Answer 11:

看起来也许和Option是要走的路。

但还需要模式匹配,使其更简单了这一类的用户。 这样,用户不需要使用instanceof并与实时类转换异常的风险投。



文章来源: How to implement List, Set, and Map in null free design?