【问题标题】:Can I have a non-empty hashmap with no keys in it?我可以有一个没有键的非空哈希图吗?
【发布时间】:2013-02-27 09:55:32
【问题描述】:

我在 java HashMap 上遇到了一个奇怪且意外的行为,在仅用于测试的部分代码上。

为了在将对象存储到会话中之前尝试为其设置唯一 ID,我使用了 if{}else{} 语句,但我发现自己的应用程序出现错误。

ID 是出于测试目的而生成的,因为目前没有数据库来实际存储数据,同时存储在 session 中。

这是我的sn-p代码:

 ...
 HttpSession session = request.getSession();
 Map<Integer, Booking> bookings = (HashMap<Integer, Booking>) session.getAttribute(SESSION_BOOKINGS);

 // Generates ID
 if (bookings == null)
 {
      bookings= new HashMap<Integer, Booking>();
      identificator = 1;
 }
 else
 {
      Object[] arrayKeys = (Object[]) bookings.keySet().toArray();
      Arrays.sort(arrayKeys);
      identificator = (Integer) arrayKeys[arrayKeys.length - 1] + 1;
 }

 ...
 //... The rest is setting the ID to the current worked on booking,
 //... putting the ID/booking pair in the bookings map
 //... and storing the map in session, which worked fine

当地图只包含一个预订时,删除地图中的预订后出现错误。当我在那之后尝试再注册一个时,我收到了一个错误,错误原因如下java.lang.ArrayIndexOutOfBoundsException: -1 和链接到我的else 语句的最后一行的跟踪:identificator = (Integer) arrayKeys[arrayKeys.length - 1] + 1;

所以:

  1. arrayKeys.length -1 == -1 // true
  2. 表示arrayKeys.length == 0 // true
  3. 这又意味着来自Map&lt;Integer,Booking&gt; bookingskeySet() 是空的

  4. 然而测试没有进入if语句

另一方面,在一个全新的会话中(在重新启动浏览器或注销并再次登录之后),测试确实按预期输入了 if 语句。

测试后,我将状态从(bookings==null)更改为
(bookings==null || bookings.isEmpty()).
进一步的测试表明,在新会话上注册预订时,仅使用 (bookings.isEmpty() 会导致 NPE。

所以我想知道一个 Map 是否有可能是非空的,其中没有任何值(显然,是的,但我也在问自己如何)以及它为什么在它之后没有返回空完全清空了?

虽然我知道在new 语句之后它是空的,但在session.getAttribute() 调用之后它是怎么来的?看起来很明显,因为 session 中还没有存储 Map,但同时因为没有 new 语句,这看起来很奇怪。

【问题讨论】:

    标签: java jakarta-ee map hashmap key


    【解决方案1】:

    如果

        if (bookings == null)
    

    是真的,比你没有地图(这不同于空地图)。

    如果else 块被执行,这意味着一个映射被引用。您对地图中的元素数量一无所知。你可能想要这样的东西:

    if (bookings == null)
    {
         bookings= new HashMap<Integer, Booking>();
         identificator = 1;
    } else if (bookings.isEmpty())
    {
         identificator = 1;
    }
    else
    {
         identificator = Collections.max(bookings.keySet()) + 1;
    }
    

    回答这个问题:

    为什么清空后没有返回null?

    看看这段代码:

    Map<Integer, Booking> map = new HashMap<>();
    

    我从未在映射中输入任何键/值对,所以它是空的。这与我将一些键/值对放入其中然后再次删除它们的状态相同。 map 是空的,但它没有理由是 null。如果是null,我们以后就不能再添加任何东西了。

    【讨论】:

      【解决方案2】:

      HashMap 可以是null(如果未初始化)或空(如果已初始化但未输入对象)。 从地图中移除对象会将其返回到“空”状态(not null)。

      new 语句为对象分配内存,并将其创建为空的HashMap(并且为空)

      【讨论】:

        【解决方案3】:

        nullempty 是完全不同的概念。当一个变量(引用类型)为空时,它不指向任何地方。你根本没有HashMap。你只有一个空的指针(不是空的HashMap)。您使用bookings = new HashMap&lt;Integer, Booking&gt;() 创建一个新的HashMap。之后你有一个 empty HashMap。你确实有一个HashMap,但里面什么都没有。

        此外,当您从HashMap 中删除所有元素时,它变为empty,而不是null。要使其成为null,您必须明确地这样做:

        bookings = null;
        

        【讨论】:

          猜你喜欢
          • 2013-06-17
          • 2020-11-02
          • 2011-09-01
          • 2011-04-29
          • 1970-01-01
          • 2015-04-19
          • 2013-09-15
          • 2011-08-03
          • 1970-01-01
          相关资源
          最近更新 更多