0

テスト専用のコードの一部で、Java HashMap で奇妙で予期しない動作が発生しました。

オブジェクトをセッションに保存する前に一意の ID を設定しようとしましたif{}else{}が、ステートメントを使用しましたが、アプリでエラーが発生しました。

ID はテスト目的で生成されます。これは、データを実際に格納するデータベースが現在存在しないためです。その間、データはセッションに格納されます。

コードのスニペットは次のとおりです。

 ...
 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

マップに予約が 1 つしか含まれていないときに、マップ内の予約を削除すると、エラーが発生しました。その後、もう 1 つ登録しようとすると、次のエラー原因とステートメントjava.lang.ArrayIndexOutOfBoundsException: -1の最後の行にリンクされたトレースでエラーが発生しました。elseidentificator = (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 が値のない非 null になる可能性があるかどうか疑問に思っていました (明らかに、そうですが、どうすればよいか自問しています)、完全に空になった後に null に戻らなかったのはなぜですか?

newそして、ステートメントの後にそれがnullであることがわかりましたが、なぜそれが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

AHashMapnull(初期化されていない場合) または空 (初期化されているがオブジェクトが入力されていない場合) です。マップからオブジェクトを削除すると、オブジェクトは「空」の状態に戻ります ( ではありません null)。

newステートメントはオブジェクトにメモリを割り当て、それを空HashMap( nullではない) として作成します。

于 2013-02-27T10:05:11.223 に答える
1

nullであることと空であることは、まったく異なる概念です。変数 (参照型) が null の場合、どこも指していません。あなたにはまったくありませんHashMap。空のポインタがあります(空の ではありませんHashMap)。HashMapを使用して新規作成しbookings = new HashMap<Integer, Booking>()ます。その後、空の HashMap. あなたは実際に を持っていますがHashMap、その中には何もありません。

また、 からすべての要素を削除すると、 nullではなくHashMapになります。それを行うには、明示的にそれを行う必要があります:null

bookings = null;
于 2013-02-27T10:06:32.813 に答える