0

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

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

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

这是我的代码片段:

 ...
 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. 这反过来意味着keySet()fromMap<Integer,Booking> bookings是空的

  4. 但是测试没有进入if语句

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

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

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

尽管我在new声明之后知道它是空的,但它在session.getAttribute()调用之后是怎么来的?这似乎很明显,因为会话中还没有存储 Map,但同时由于没有new声明,这看起来很奇怪。

4

3 回答 3

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我们以后就不能再添加任何东西了。

于 2013-02-27T10:03:25.663 回答
1

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

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

于 2013-02-27T10:05:11.223 回答
1

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

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

bookings = null;
于 2013-02-27T10:06:32.813 回答