Apache Commons Collections OrderedMap
1.概述
Apache Commons Collections庫提供了一些有用的類,這些類是對Java Collections Framework的補充。
在本文中,我們將回顧接口OrderedMap ,該接口擴展了java.util.Map 。
2. Maven依賴
我們需要做的第一件事是在我們的pom.xml中添加Maven依賴項:
<dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-collections4</artifactId>
 <version>4.1</version>
 </dependency>
您可以在Maven Central存儲庫中找到該庫的最新版本。
3. OrderedMap屬性
簡而言之,一個實現OrderedMap接口的地圖:
- 儘管鍵組未排序,但仍保持鍵組的順序
 - 可以使用以下方法在兩個方向上進行迭代: firstKey()和nextKey() ,或者lastKey()和previousKey()
 - 可以用MapIterator遍歷(也由庫提供)
 - 提供查找,更改,刪除或替換元素的方法
 
4.使用OrderedMap
讓我們在測試類中設置跑步者及其年齡的OrderedMap 。我們將使用LinkedMap –庫中提供的OrderedMap實現之一。
首先,讓我們設置跑步者和年齡的數組,以用於加載地圖並驗證值的順序:
public class OrderMapUnitTest {
 private String[] names = {"Emily", "Mathew", "Rose", "John", "Anna"};
 private Integer[] ages = {37, 28, 40, 36, 21};
 private LinkedMap<String, Integer> runnersLinkedMap;
 //...
 }
現在,讓我們初始化地圖:
@Before
 public void createRunners() {
 this.runnersLinkedMap = new LinkedMap<>();
 for (int i = 0; i < RUNNERS_COUNT; i++) {
 runners.put(this.names[i], this.ages[i]);
 }
 }
4.1 正向迭代
讓我們看看如何使用正向迭代器:
@Test
 public void givenALinkedMap_whenIteratedForwards_thenPreservesOrder() {
 String name = this.runnersLinkedMap.firstKey();
 int i = 0;
 while (name != null) {
 assertEquals(name, names[i]);
 name = this.runnersLinkedMap.nextKey(name);
 i++;
 }
 }
注意,當我們到達最後一個鍵時,方法nextKey()將返回一個空值。
4.2 向後迭代
現在,從最後一個鍵開始進行迭代:
@Test
 public void givenALinkedMap_whenIteratedBackwards_thenPreservesOrder() {
 String name = this.runnersLinkedMap.lastKey();
 int i = RUNNERS_COUNT - 1;
 while (name != null) {
 assertEquals(name, this.names[i]);
 name = this.runnersLinkedMap.previousKey(name);
 i--;
 }
 }
一旦到達第一個鍵, previousKey()方法將返回null。
4.3 MapIterator示例
現在,讓我們使用mapIterator()方法獲取一個MapIterator,因為它展示了它如何保留數組名稱和年齡中定義的跑步者的順序:
@Test
 public void givenALinkedMap_whenIteratedWithMapIterator_thenPreservesOrder() {
 OrderedMapIterator<String, Integer> runnersIterator
 = this.runnersLinkedMap.mapIterator();
 int i = 0;
 while (runnersIterator.hasNext()) {
 runnersIterator.next();
 assertEquals(runnersIterator.getKey(), this.names[i]);
 assertEquals(runnersIterator.getValue(), this.ages[i]);
 i++;
 }
 }
4.4 移除元素
最後,讓我們檢查一下如何通過索引或對象刪除元素:
@Test
 public void givenALinkedMap_whenElementRemoved_thenSizeDecrease() {
 LinkedMap<String, Integer> lmap
 = (LinkedMap<String, Integer>) this.runnersLinkedMap;
 Integer johnAge = lmap.remove("John");
 assertEquals(johnAge, new Integer(36));
 assertEquals(lmap.size(), RUNNERS_COUNT - 1);
 Integer emilyAge = lmap.remove(0);
 assertEquals(emilyAge, new Integer(37));
 assertEquals(lmap.size(), RUNNERS_COUNT - 2);
 }
5.提供的實現
當前,在庫的版本4.1中,有OrderedMap接口的兩種實現– ListOrderedMap和LinkedMap 。
ListOrderedMap使用java.util.List跟踪鍵集的順序。它是OrderedMap的裝飾器,可以使用靜態方法ListOrderedMap.decorate(Map map)從任何Map創建。
LinkedMap基於HashMap,並通過允許雙向迭代和OrderedMap接口的其他方法對其進行了改進。
兩種實現還提供了OrderedMap接口之外的三種方法:
-   asList() –獲取類型為List 
的列表 (其中K為鍵的類型),保留地圖的順序 - get(int index) –在位置索引處獲取元素,與接口中提供的方法get(Object o)相反
 - indexOf(Object o) –獲取有序映射中對象o的索引
 
我們可以將OrderedMap轉換為LinkedMap以使用asList()方法:
@Test
 public void givenALinkedMap_whenConvertedToList_thenMatchesKeySet() {
 LinkedMap<String, Integer> lmap
 = (LinkedMap<String, Integer>) this.runnersLinkedMap;
 List<String> listKeys = new ArrayList<>();
 listKeys.addAll(this.runnersLinkedMap.keySet());
 List<String> linkedMap = lmap.asList();
 assertEquals(listKeys, linkedMap);
 }
然後,我們可以檢查LinkedMap實現中indexOf(Object o)和get(int index)方法的功能:
@Test
 public void givenALinkedMap_whenSearchByIndexIsUsed_thenMatchesConstantArray() {
 LinkedMap<String, Integer> lmap
 = (LinkedMap<String, Integer>) this.runnersLinkedMap;
 for (int i = 0; i < RUNNERS_COUNT; i++) {
 String name = lmap.get(i);
 assertEquals(name, this.names[i]);
 assertEquals(lmap.indexOf(this.names[i]), i);
 }
 }
六,結論
在本快速教程中,我們回顧了OrderedMap接口及其主要方法和實現。
有關更多信息,請參閱Apache Commons Collections庫的JavaDoc 。
與往常一樣,本文的完整測試類包含使用LinkedMap和ListOrderedMap的相似測試用例,可以從GitHub項目中下載。