1 /* 2 * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8005698 27 * @run testng/othervm -Dtest.map.collisions.shortrun=true InPlaceOpsCollisions 28 * @summary Ensure overrides of in-place operations in Maps behave well with lots of collisions. 29 */ 30 31 import java.util.Arrays; 32 import java.util.Comparator; 33 import java.util.HashMap; 34 import java.util.Iterator; 35 import java.util.LinkedHashMap; 36 import java.util.Map; 37 import java.util.TreeMap; 38 import java.util.function.BiFunction; 39 import java.util.function.Function; 40 import java.util.function.Supplier; 41 42 import org.testng.annotations.DataProvider; 43 import org.testng.annotations.Test; 44 import static org.testng.Assert.assertTrue; 45 import static org.testng.Assert.assertFalse; 46 import static org.testng.Assert.assertEquals; 47 import static org.testng.Assert.assertNull; 48 49 public class InPlaceOpsCollisions extends MapWithCollisionsProviders { 50 51 @Test(dataProvider = "mapsWithObjectsAndStrings") 52 void testPutIfAbsent(String desc, Supplier<Map<Object, Object>> ms, Object val) { 53 Map<Object, Object> map = ms.get(); 54 Object[] keys = map.keySet().toArray(); 55 Object retVal; 56 removeOddKeys(map, keys); 57 for (int i = 0; i < keys.length; i++) { 58 retVal = map.putIfAbsent(keys[i], val); 59 if (i % 2 == 0) { // even: not absent, not put 60 61 assertEquals(retVal, keys[i], 62 String.format("putIfAbsent: (%s[%d]) retVal", desc, i)); 63 assertEquals(keys[i], map.get(keys[i]), 64 String.format("putIfAbsent: get(%s[%d])", desc, i)); 65 assertTrue(map.containsValue(keys[i]), 66 String.format("putIfAbsent: containsValue(%s[%d])", desc, i)); 67 } else { // odd: absent, was put 68 assertNull(retVal, 69 String.format("putIfAbsent: (%s[%d]) retVal", desc, i)); 70 assertEquals(val, map.get(keys[i]), 71 String.format("putIfAbsent: get(%s[%d])", desc, i)); 72 assertFalse(map.containsValue(keys[i]), 73 String.format("putIfAbsent: !containsValue(%s[%d])", desc, i)); 74 } 75 assertTrue(map.containsKey(keys[i]), 76 String.format("insertion: containsKey(%s[%d])", desc, i)); 77 } 78 assertEquals(map.size(), keys.length, 79 String.format("map expected size m%d != k%d", map.size(), keys.length)); 80 } 81 82 @Test(dataProvider = "nullValueFriendlyMaps") 83 void testPutIfAbsentOverwriteNull(String desc, Supplier<Map<Object, Object>> ms) { 84 Map<Object, Object> map = ms.get(); 85 map.put("key", null); 86 assertEquals(map.size(), 1, desc + ": size != 1"); 87 assertTrue(map.containsKey("key"), desc + ": does not have key"); 88 assertNull(map.get("key"), desc + ": value is not null"); 89 map.putIfAbsent("key", "value"); // must rewrite 90 assertEquals(map.size(), 1, desc + ": size != 1"); 91 assertTrue(map.containsKey("key"), desc + ": does not have key"); 92 assertEquals(map.get("key"), "value", desc + ": value is not 'value'"); 93 } 94 95 @Test(dataProvider = "mapsWithObjectsAndStrings") 96 void testRemoveMapping(String desc, Supplier<Map<Object, Object>> ms, Object val) { 97 Map<Object, Object> map = ms.get(); 98 Object[] keys = map.keySet().toArray(); 99 boolean removed; 100 int removes = 0; 101 remapOddKeys(map, keys, val); 102 for (int i = 0; i < keys.length; i++) { 103 removed = map.remove(keys[i], keys[i]); 104 if (i % 2 == 0) { // even: original mapping, should be removed 105 assertTrue(removed, 106 String.format("removeMapping: retVal(%s[%d])", desc, i)); 107 assertNull(map.get(keys[i]), 108 String.format("removeMapping: get(%s[%d])", desc, i)); 109 assertFalse(map.containsKey(keys[i]), 110 String.format("removeMapping: !containsKey(%s[%d])", desc, i)); 111 assertFalse(map.containsValue(keys[i]), 112 String.format("removeMapping: !containsValue(%s[%d])", desc, i)); 113 removes++; 114 } else { // odd: new mapping, not removed 115 assertFalse(removed, 116 String.format("removeMapping: retVal(%s[%d])", desc, i)); 117 assertEquals(val, map.get(keys[i]), 118 String.format("removeMapping: get(%s[%d])", desc, i)); 119 assertTrue(map.containsKey(keys[i]), 120 String.format("removeMapping: containsKey(%s[%d])", desc, i)); 121 assertTrue(map.containsValue(val), 122 String.format("removeMapping: containsValue(%s[%d])", desc, i)); 123 } 124 } 125 assertEquals(map.size(), keys.length - removes, 126 String.format("map expected size m%d != k%d", map.size(), keys.length - removes)); 127 } 128 129 @Test(dataProvider = "mapsWithObjectsAndStrings") 130 void testReplaceOldValue(String desc, Supplier<Map<Object, Object>> ms, Object val) { 131 // remap odds to val 132 // call replace to replace for val, for all keys 133 // check that all keys map to value from keys array 134 Map<Object, Object> map = ms.get(); 135 Object[] keys = map.keySet().toArray(); 136 boolean replaced; 137 remapOddKeys(map, keys, val); 138 139 for (int i = 0; i < keys.length; i++) { 140 replaced = map.replace(keys[i], val, keys[i]); 141 if (i % 2 == 0) { // even: original mapping, should not be replaced 142 assertFalse(replaced, 143 String.format("replaceOldValue: retVal(%s[%d])", desc, i)); 144 } else { // odd: new mapping, should be replaced 145 assertTrue(replaced, 146 String.format("replaceOldValue: get(%s[%d])", desc, i)); 147 } 148 assertEquals(keys[i], map.get(keys[i]), 149 String.format("replaceOldValue: get(%s[%d])", desc, i)); 150 assertTrue(map.containsKey(keys[i]), 151 String.format("replaceOldValue: containsKey(%s[%d])", desc, i)); 152 assertTrue(map.containsValue(keys[i]), 153 String.format("replaceOldValue: containsValue(%s[%d])", desc, i)); 154 } 155 assertFalse(map.containsValue(val), 156 String.format("replaceOldValue: !containsValue(%s[%s])", desc, val)); 157 assertEquals(map.size(), keys.length, 158 String.format("map expected size m%d != k%d", map.size(), keys.length)); 159 } 160 161 @Test(dataProvider = "mapsWithObjectsAndStrings") 162 void testReplaceIfMapped(String desc, Supplier<Map<Object, Object>> ms, Object val) { 163 // remove odd keys 164 // call replace for all keys[] 165 // odd keys should remain absent, even keys should be mapped to EXTRA, no value from keys[] should be in map 166 Map<Object, Object> map = ms.get(); 167 Object[] keys = map.keySet().toArray(); 168 int expectedSize1 = 0; 169 removeOddKeys(map, keys); 170 int expectedSize2 = map.size(); 171 172 for (int i = 0; i < keys.length; i++) { 173 Object retVal = map.replace(keys[i], val); 174 if (i % 2 == 0) { // even: still in map, should be replaced 175 assertEquals(retVal, keys[i], 176 String.format("replaceIfMapped: retVal(%s[%d])", desc, i)); 177 assertEquals(val, map.get(keys[i]), 178 String.format("replaceIfMapped: get(%s[%d])", desc, i)); 179 assertTrue(map.containsKey(keys[i]), 180 String.format("replaceIfMapped: containsKey(%s[%d])", desc, i)); 181 expectedSize1++; 182 } else { // odd: was removed, should not be replaced 183 assertNull(retVal, 184 String.format("replaceIfMapped: retVal(%s[%d])", desc, i)); 185 assertNull(map.get(keys[i]), 186 String.format("replaceIfMapped: get(%s[%d])", desc, i)); 187 assertFalse(map.containsKey(keys[i]), 188 String.format("replaceIfMapped: containsKey(%s[%d])", desc, i)); 189 } 190 assertFalse(map.containsValue(keys[i]), 191 String.format("replaceIfMapped: !containsValue(%s[%d])", desc, i)); 192 } 193 assertTrue(map.containsValue(val), 194 String.format("replaceIfMapped: containsValue(%s[%s])", desc, val)); 195 assertEquals(map.size(), expectedSize1, 196 String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1)); 197 assertEquals(map.size(), expectedSize2, 198 String.format("map expected size#2 m%d != k%d", map.size(), expectedSize2)); 199 200 } 201 202 private static <T> void testComputeIfAbsent(Map<T, T> map, String desc, T[] keys, 203 Function<T, T> mappingFunction) { 204 // remove a third of the keys 205 // call computeIfAbsent for all keys, func returns EXTRA 206 // check that removed keys now -> EXTRA, other keys -> original val 207 T expectedVal = mappingFunction.apply(keys[0]); 208 T retVal; 209 int expectedSize = 0; 210 removeThirdKeys(map, keys); 211 for (int i = 0; i < keys.length; i++) { 212 retVal = map.computeIfAbsent(keys[i], mappingFunction); 213 if (i % 3 != 2) { // key present, not computed 214 assertEquals(retVal, keys[i], 215 String.format("computeIfAbsent: (%s[%d]) retVal", desc, i)); 216 assertEquals(keys[i], map.get(keys[i]), 217 String.format("computeIfAbsent: get(%s[%d])", desc, i)); 218 assertTrue(map.containsValue(keys[i]), 219 String.format("computeIfAbsent: containsValue(%s[%d])", desc, i)); 220 assertTrue(map.containsKey(keys[i]), 221 String.format("insertion: containsKey(%s[%d])", desc, i)); 222 expectedSize++; 223 } else { // key absent, computed unless function return null 224 assertEquals(retVal, expectedVal, 225 String.format("computeIfAbsent: (%s[%d]) retVal", desc, i)); 226 assertEquals(expectedVal, map.get(keys[i]), 227 String.format("computeIfAbsent: get(%s[%d])", desc, i)); 228 assertFalse(map.containsValue(keys[i]), 229 String.format("computeIfAbsent: !containsValue(%s[%d])", desc, i)); 230 // mapping should not be added if function returns null 231 assertTrue(map.containsKey(keys[i]) != (expectedVal == null), 232 String.format("insertion: containsKey(%s[%d])", desc, i)); 233 if (expectedVal != null) { 234 expectedSize++; 235 } 236 } 237 } 238 if (expectedVal != null) { 239 assertTrue(map.containsValue(expectedVal), 240 String.format("computeIfAbsent: containsValue(%s[%s])", desc, expectedVal)); 241 } 242 assertEquals(map.size(), expectedSize, 243 String.format("map expected size m%d != k%d", map.size(), expectedSize)); 244 } 245 246 @Test(dataProvider = "mapsWithObjectsAndStrings") 247 void testComputeIfAbsentNonNull(String desc, Supplier<Map<Object, Object>> ms, Object val) { 248 Map<Object, Object> map = ms.get(); 249 Object[] keys = map.keySet().toArray(); 250 testComputeIfAbsent(map, desc, keys, (k) -> val); 251 } 252 253 @Test(dataProvider = "mapsWithObjectsAndStrings") 254 void testComputeIfAbsentNull(String desc, Supplier<Map<Object, Object>> ms, Object val) { 255 Map<Object, Object> map = ms.get(); 256 Object[] keys = map.keySet().toArray(); 257 testComputeIfAbsent(map, desc, keys, (k) -> null); 258 } 259 260 private static <T> void testComputeIfPresent(Map<T, T> map, String desc, T[] keys, 261 BiFunction<T, T, T> mappingFunction) { 262 // remove a third of the keys 263 // call testComputeIfPresent for all keys[] 264 // removed keys should remain absent, even keys should be mapped to $RESULT 265 // no value from keys[] should be in map 266 T funcResult = mappingFunction.apply(keys[0], keys[0]); 267 int expectedSize1 = 0; 268 removeThirdKeys(map, keys); 269 270 for (int i = 0; i < keys.length; i++) { 271 T retVal = map.computeIfPresent(keys[i], mappingFunction); 272 if (i % 3 != 2) { // key present 273 if (funcResult == null) { // was removed 274 assertFalse(map.containsKey(keys[i]), 275 String.format("replaceIfMapped: containsKey(%s[%d])", desc, i)); 276 } else { // value was replaced 277 assertTrue(map.containsKey(keys[i]), 278 String.format("replaceIfMapped: containsKey(%s[%d])", desc, i)); 279 expectedSize1++; 280 } 281 assertEquals(retVal, funcResult, 282 String.format("computeIfPresent: retVal(%s[%s])", desc, i)); 283 assertEquals(funcResult, map.get(keys[i]), 284 String.format("replaceIfMapped: get(%s[%d])", desc, i)); 285 286 } else { // odd: was removed, should not be replaced 287 assertNull(retVal, 288 String.format("replaceIfMapped: retVal(%s[%d])", desc, i)); 289 assertNull(map.get(keys[i]), 290 String.format("replaceIfMapped: get(%s[%d])", desc, i)); 291 assertFalse(map.containsKey(keys[i]), 292 String.format("replaceIfMapped: containsKey(%s[%d])", desc, i)); 293 } 294 assertFalse(map.containsValue(keys[i]), 295 String.format("replaceIfMapped: !containsValue(%s[%d])", desc, i)); 296 } 297 assertEquals(map.size(), expectedSize1, 298 String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1)); 299 } 300 301 @Test(dataProvider = "mapsWithObjectsAndStrings") 302 void testComputeIfPresentNonNull(String desc, Supplier<Map<Object, Object>> ms, Object val) { 303 Map<Object, Object> map = ms.get(); 304 Object[] keys = map.keySet().toArray(); 305 testComputeIfPresent(map, desc, keys, (k, v) -> val); 306 } 307 308 @Test(dataProvider = "mapsWithObjectsAndStrings") 309 void testComputeIfPresentNull(String desc, Supplier<Map<Object, Object>> ms, Object val) { 310 Map<Object, Object> map = ms.get(); 311 Object[] keys = map.keySet().toArray(); 312 testComputeIfPresent(map, desc, keys, (k, v) -> null); 313 } 314 315 @Test(dataProvider = "hashMapsWithObjects") 316 void testComputeNonNull(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) { 317 // remove a third of the keys 318 // call compute() for all keys[] 319 // all keys should be present: removed keys -> EXTRA, others to k-1 320 Map<IntKey, IntKey> map = ms.get(); 321 IntKey[] keys = map.keySet().stream().sorted().toArray(IntKey[]::new); 322 BiFunction<IntKey, IntKey, IntKey> mappingFunction = (k, v) -> { 323 if (v == null) { 324 return val; 325 } else { 326 return keys[k.getValue() - 1]; 327 } 328 }; 329 removeThirdKeys(map, keys); 330 for (int i = 1; i < keys.length; i++) { 331 IntKey retVal = map.compute(keys[i], mappingFunction); 332 if (i % 3 != 2) { // key present, should be mapped to k-1 333 assertEquals(retVal, keys[i - 1], 334 String.format("compute: retVal(%s[%d])", desc, i)); 335 assertEquals(keys[i - 1], map.get(keys[i]), 336 String.format("compute: get(%s[%d])", desc, i)); 337 } else { // odd: was removed, should be replaced with EXTRA 338 assertEquals(retVal, val, 339 String.format("compute: retVal(%s[%d])", desc, i)); 340 assertEquals(val, map.get(keys[i]), 341 String.format("compute: get(%s[%d])", desc, i)); 342 } 343 assertTrue(map.containsKey(keys[i]), 344 String.format("compute: containsKey(%s[%d])", desc, i)); 345 } 346 assertEquals(map.size(), keys.length, 347 String.format("map expected size#1 m%d != k%d", map.size(), keys.length)); 348 assertTrue(map.containsValue(val), 349 String.format("compute: containsValue(%s[%s])", desc, val)); 350 assertFalse(map.containsValue(null), 351 String.format("compute: !containsValue(%s,[null])", desc)); 352 } 353 354 @Test(dataProvider = "mapsWithObjectsAndStrings") 355 void testComputeNull(String desc, Supplier<Map<Object, Object>> ms, Object val) { 356 // remove a third of the keys 357 // call compute() for all keys[] 358 // removed keys should -> EXTRA 359 // for other keys: func returns null, should have no mapping 360 Map<Object, Object> map = ms.get(); 361 Object[] keys = map.keySet().toArray(); 362 BiFunction<Object, Object, Object> mappingFunction = (k, v) -> { 363 // if absent/null -> EXTRA 364 // if present -> null 365 if (v == null) { 366 return val; 367 } else { 368 return null; 369 } 370 }; 371 int expectedSize = 0; 372 removeThirdKeys(map, keys); 373 for (int i = 0; i < keys.length; i++) { 374 Object retVal = map.compute(keys[i], mappingFunction); 375 if (i % 3 != 2) { // key present, func returned null, should be absent from map 376 assertNull(retVal, 377 String.format("compute: retVal(%s[%d])", desc, i)); 378 assertNull(map.get(keys[i]), 379 String.format("compute: get(%s[%d])", desc, i)); 380 assertFalse(map.containsKey(keys[i]), 381 String.format("compute: containsKey(%s[%d])", desc, i)); 382 assertFalse(map.containsValue(keys[i]), 383 String.format("compute: containsValue(%s[%s])", desc, i)); 384 } else { // odd: was removed, should now be mapped to EXTRA 385 assertEquals(retVal, val, 386 String.format("compute: retVal(%s[%d])", desc, i)); 387 assertEquals(val, map.get(keys[i]), 388 String.format("compute: get(%s[%d])", desc, i)); 389 assertTrue(map.containsKey(keys[i]), 390 String.format("compute: containsKey(%s[%d])", desc, i)); 391 expectedSize++; 392 } 393 } 394 assertTrue(map.containsValue(val), 395 String.format("compute: containsValue(%s[%s])", desc, val)); 396 assertEquals(map.size(), expectedSize, 397 String.format("map expected size#1 m%d != k%d", map.size(), expectedSize)); 398 } 399 400 @Test(dataProvider = "hashMapsWithObjects") 401 void testMergeNonNull(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) { 402 // remove a third of the keys 403 // call merge() for all keys[] 404 // all keys should be present: removed keys now -> EXTRA, other keys -> k-1 405 Map<IntKey, IntKey> map = ms.get(); 406 IntKey[] keys = map.keySet().stream().sorted().toArray(IntKey[]::new); 407 408 // Map to preceding key 409 BiFunction<IntKey, IntKey, IntKey> mappingFunction 410 = (k, v) -> keys[k.getValue() - 1]; 411 removeThirdKeys(map, keys); 412 for (int i = 1; i < keys.length; i++) { 413 IntKey retVal = map.merge(keys[i], val, mappingFunction); 414 if (i % 3 != 2) { // key present, should be mapped to k-1 415 assertEquals(retVal, keys[i - 1], 416 String.format("compute: retVal(%s[%d])", desc, i)); 417 assertEquals(keys[i - 1], map.get(keys[i]), 418 String.format("compute: get(%s[%d])", desc, i)); 419 } else { // odd: was removed, should be replaced with EXTRA 420 assertEquals(retVal, val, 421 String.format("compute: retVal(%s[%d])", desc, i)); 422 assertEquals(val, map.get(keys[i]), 423 String.format("compute: get(%s[%d])", desc, i)); 424 } 425 assertTrue(map.containsKey(keys[i]), 426 String.format("compute: containsKey(%s[%d])", desc, i)); 427 } 428 429 assertEquals(map.size(), keys.length, 430 String.format("map expected size#1 m%d != k%d", map.size(), keys.length)); 431 assertTrue(map.containsValue(val), 432 String.format("compute: containsValue(%s[%s])", desc, val)); 433 assertFalse(map.containsValue(null), 434 String.format("compute: !containsValue(%s,[null])", desc)); 435 } 436 437 @Test(dataProvider = "mapsWithObjectsAndStrings") 438 void testMergeNull(String desc, Supplier<Map<Object, Object>> ms, Object val) { 439 // remove a third of the keys 440 // call merge() for all keys[] 441 // result: removed keys -> EXTRA, other keys absent 442 443 Map<Object, Object> map = ms.get(); 444 Object[] keys = map.keySet().toArray(); 445 BiFunction<Object, Object, Object> mappingFunction = (k, v) -> null; 446 int expectedSize = 0; 447 removeThirdKeys(map, keys); 448 for (int i = 0; i < keys.length; i++) { 449 Object retVal = map.merge(keys[i], val, mappingFunction); 450 if (i % 3 != 2) { // key present, func returned null, should be absent from map 451 assertNull(retVal, 452 String.format("compute: retVal(%s[%d])", desc, i)); 453 assertNull(map.get(keys[i]), 454 String.format("compute: get(%s[%d])", desc, i)); 455 assertFalse(map.containsKey(keys[i]), 456 String.format("compute: containsKey(%s[%d])", desc, i)); 457 } else { // odd: was removed, should now be mapped to EXTRA 458 assertEquals(retVal, val, 459 String.format("compute: retVal(%s[%d])", desc, i)); 460 assertEquals(val, map.get(keys[i]), 461 String.format("compute: get(%s[%d])", desc, i)); 462 assertTrue(map.containsKey(keys[i]), 463 String.format("compute: containsKey(%s[%d])", desc, i)); 464 expectedSize++; 465 } 466 assertFalse(map.containsValue(keys[i]), 467 String.format("compute: containsValue(%s[%s])", desc, i)); 468 } 469 assertTrue(map.containsValue(val), 470 String.format("compute: containsValue(%s[%s])", desc, val)); 471 assertEquals(map.size(), expectedSize, 472 String.format("map expected size#1 m%d != k%d", map.size(), expectedSize)); 473 } 474 475 /* 476 * Remove half of the keys 477 */ 478 private static <T> void removeOddKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) { 479 int removes = 0; 480 for (int i = 0; i < keys.length; i++) { 481 if (i % 2 != 0) { 482 map.remove(keys[i]); 483 removes++; 484 } 485 } 486 assertEquals(map.size(), keys.length - removes, 487 String.format("map expected size m%d != k%d", map.size(), keys.length - removes)); 488 } 489 490 /* 491 * Remove every third key 492 * This will hopefully leave some removed keys in TreeBins for, e.g., computeIfAbsent 493 * w/ a func that returns null. 494 * 495 * TODO: consider using this in other tests (and maybe adding a remapThirdKeys) 496 */ 497 private static <T> void removeThirdKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) { 498 int removes = 0; 499 for (int i = 0; i < keys.length; i++) { 500 if (i % 3 == 2) { 501 map.remove(keys[i]); 502 removes++; 503 } 504 } 505 assertEquals(map.size(), keys.length - removes, 506 String.format("map expected size m%d != k%d", map.size(), keys.length - removes)); 507 } 508 509 /* 510 * Re-map the odd-numbered keys to map to the EXTRA value 511 */ 512 private static <T> void remapOddKeys(Map<T, T> map, T[] keys, T val) { 513 for (int i = 0; i < keys.length; i++) { 514 if (i % 2 != 0) { 515 map.put(keys[i], val); 516 } 517 } 518 } 519 520 @DataProvider 521 public Iterator<Object[]> nullValueFriendlyMaps() { 522 return Arrays.asList( 523 new Object[]{"HashMap", (Supplier<Map<?, ?>>) HashMap::new}, 524 new Object[]{"LinkedHashMap", (Supplier<Map<?, ?>>) LinkedHashMap::new}, 525 new Object[]{"TreeMap", (Supplier<Map<?, ?>>) TreeMap::new}, 526 new Object[]{"TreeMap(cmp)", (Supplier<Map<?, ?>>) () -> new TreeMap<>(Comparator.reverseOrder())} 527 ).iterator(); 528 } 529 }