Вопрос

Я понимаю, что набор, возвращенный из метода Keyset () карты, не гарантирует какой -либо конкретный заказ.

Мой вопрос: гарантирует ли это такой же заказ на несколько итераций. Например

Map<K,V> map = getMap();

for( K k : map.keySet() )
{
}

...

for( K k : map.keySet() )
{
}

В приведенном выше коде, предполагая, что карта нет Модифицировано, будет ли итерация над Кейзами в том же порядке. Используя солнце JDK15 IT делает Итерация в том же порядке, но прежде чем я буду зависеть от этого поведения, я хотел бы знать, сделают ли все JDK то же самое.

РЕДАКТИРОВАТЬ

Я вижу из ответов, что я не могу зависеть от этого. Очень жаль. Я надеялся сойти с рук, не приходится создавать новую коллекцию, чтобы гарантировать мой заказ. Мой код необходим для того, чтобы перевернуть, сделать некоторую логику, а затем снова итерацию с тем же упорядочением. Я просто создам новый ArrayList из Keyset, который гарантирует заказ.

Это было полезно?

Решение

Если в документации API не указано, что в документации API вы не должны зависеть от этого. Поведение может даже измениться от одного выпуска JDK к другому, даже с JDK того же поставщика.

Вы можете легко получить набор, а затем просто сортировать его самостоятельно, верно?

Другие советы

Вы можете использовать LinkedHashmap Если вам нужен хэшмап, чей порядок итерации не меняется.

Более того, вы должны всегда использовать его, если вы выполняете, через коллекцию. Итерация над входом или Keyset Hashmap намного медленнее, чем над LinkedHashmap.

Карта - это всего лишь интерфейс (а не класс), что означает, что базовый класс, который реализует его (и их много), может вести себя по -разному, и контракт для Keyset () в API не указывает на то, что требуется последовательная итерация.

Если вы смотрите на определенный класс, который реализует карту (HashMap, LinkedHashmap, TreeMap и т. Д.), то вы можете увидеть, как она реализует функцию Keyset (), чтобы определить, какое будет поведение, проверив источник, вам нужно будет Действительно внимательно посмотрите на алгоритм, чтобы увидеть, сохраняется ли свойство, которое вы ищете (то есть согласованный порядок итерации, когда на карте не было никаких вставки/удаления между итерациями). Например, источник HashMap - это здесь (Open JDK 6): http://www.docjar.com/html/api/java/util/hashmap.java.html

Это может сильно варьироваться от одного JDK к другому, поэтому я определенно не буду на это полагаться.

При этом, если вам действительно нужно последовательный заказ итерации, вы можете попробовать LinkedHashmap.

API для карты не гарантирует Любые Заказ вообще, даже между несколькими вызовами метода на одном и том же объекте.

На практике я был бы очень удивлен, если бы порядок итерации изменился для нескольких последующих вызовов (при условии, что сама карта не изменилась между ними) - но вы не должны (и в соответствии с API не может) полагаться на это.

Редактировать - если вы хотите полагаться на то, что порядок итерации будет последовательным, то вы хотите SortedMap который предоставляет именно эти гарантии.

Просто для развлечения я решил написать какой -нибудь код, который вы можете использовать, чтобы гарантировать случайный заказ каждый раз. Это полезно, чтобы вы могли поймать случаи, когда вы зависите от заказа, но вы не должны быть. Если вы хотите зависеть от порядка, чем, как сказали другие, вы должны использовать SortedMap. Если вы просто используете карту и случайно полагаться на заказ, то использование следующего рандомитератора поймает это. Я бы использовал его только в тестировании кода, так как он использует больше памяти, а не это сделало бы.

Вы также можете обернуть карту (или набор), чтобы они вернули Randomeiterator, который затем позволил бы вам использовать свой цикл.

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class Main
{
    private Main()
    {
    }

    public static void main(final String[] args)
    {
        final Map<String, String> items;

        items = new HashMap<String, String>();
        items.put("A", "1");
        items.put("B", "2");
        items.put("C", "3");
        items.put("D", "4");
        items.put("E", "5");
        items.put("F", "6");
        items.put("G", "7");

        display(items.keySet().iterator());
        System.out.println("---");

        display(items.keySet().iterator());
        System.out.println("---");

        display(new RandomIterator<String>(items.keySet().iterator()));
        System.out.println("---");

        display(new RandomIterator<String>(items.keySet().iterator()));
        System.out.println("---");
    }

    private static <T> void display(final Iterator<T> iterator)
    {
        while(iterator.hasNext())
        {
            final T item;

            item = iterator.next();
            System.out.println(item);
        }
    }
}

class RandomIterator<T>
    implements Iterator<T>
{
    private final Iterator<T> iterator;

    public RandomIterator(final Iterator<T> i)
    {
        final List<T> items;

        items = new ArrayList<T>();

        while(i.hasNext())
        {
            final T item;

            item = i.next();
            items.add(item);
        }

        Collections.shuffle(items);
        iterator = items.iterator();
    }

    public boolean hasNext()
    {
        return (iterator.hasNext());
    }

    public T next()
    {
        return (iterator.next());
    }

    public void remove()
    {
        iterator.remove();
    }
}

HashMap не гарантирует, что порядок карты останется постоянным с течением времени.

Это не должно быть. Функция Keyset на карте возвращает набор, и метод итератора набора говорит об этом в своей документации:

«Возвращает итератор над элементами в этом наборе. Элементы возвращаются в любом конкретном порядке (если этот набор не является экземпляром какого -либо класса, который обеспечивает гарантию)».

Таким образом, если вы не используете один из этих классов с гарантией, их нет.

Карта - это интерфейс и не определяет в документации, что порядок должен быть таким же. Это означает, что вы не можете полагаться на заказ. Но если вы управляете реализацией карты, возвращаемой getMap (), то вы можете использовать LinkedHashmap или TreeMap и все время получить один и тот же порядок ключей/значений.

По логике, если в контракте говорится, что «конкретный заказ не гарантирован», и, поскольку «заказ вышел один раз» - это определенный порядок, тогда ответ - нет, вы не можете зависеть от того, что он выходит одинаково дважды.

Я согласен с LinkedHashmap. Просто вкладывая свои выводы и опыт, когда я сталкивался с проблемой, когда я пытался сортировать Hashmap от Keys.

Мой код для создания HashMap:

HashMap<Integer, String> map;

@Before
public void initData() {
    map = new HashMap<>();

    map.put(55, "John");
    map.put(22, "Apple");
    map.put(66, "Earl");
    map.put(77, "Pearl");
    map.put(12, "George");
    map.put(6, "Rocky");

}

У меня есть функция Showmap, которая печатает записи карты:

public void showMap (Map<Integer, String> map1) {
    for (Map.Entry<Integer,  String> entry: map1.entrySet()) {
        System.out.println("[Key: "+entry.getKey()+ " , "+"Value: "+entry.getValue() +"] ");

    }

}

Теперь, когда я печатаю карту перед сортировкой, она печатает следующую последовательность:

Map before sorting : 
[Key: 66 , Value: Earl] 
[Key: 22 , Value: Apple] 
[Key: 6 , Value: Rocky] 
[Key: 55 , Value: John] 
[Key: 12 , Value: George] 
[Key: 77 , Value: Pearl] 

Который в основном отличается от порядка, в котором были помещены ключи карты.

Теперь, когда я сортирую его с клавишами карты:

    List<Map.Entry<Integer, String>> entries = new ArrayList<>(map.entrySet());

    Collections.sort(entries, new Comparator<Entry<Integer, String>>() {

        @Override
        public int compare(Entry<Integer, String> o1, Entry<Integer, String> o2) {

            return o1.getKey().compareTo(o2.getKey());
        }
    });

    HashMap<Integer, String> sortedMap = new LinkedHashMap<>();

    for (Map.Entry<Integer, String> entry : entries) {
        System.out.println("Putting key:"+entry.getKey());
        sortedMap.put(entry.getKey(), entry.getValue());
    }

    System.out.println("Map after sorting:");

    showMap(sortedMap);

out pult:

Sorting by keys : 
Putting key:6
Putting key:12
Putting key:22
Putting key:55
Putting key:66
Putting key:77
Map after sorting:
[Key: 66 , Value: Earl] 
[Key: 6 , Value: Rocky] 
[Key: 22 , Value: Apple] 
[Key: 55 , Value: John] 
[Key: 12 , Value: George] 
[Key: 77 , Value: Pearl] 

Вы можете увидеть разницу в порядке ключей. Сортированный порядок ключей в порядке, но клавиши копированной карты снова в том же порядке на более ранней карте. Я не знаю, является ли это действительно, чтобы сказать, но для двух хэшмапов с теми же клавишами порядок ключей одинаково. Это подразумевает утверждение о том, что порядок ключей не гарантируется, но может быть одинаковым для двух карт с одинаковыми ключами из -за неотъемлемой природы алгоритма вставки клавиш, если внедрение Hashmap этой версии JVM.

Теперь, когда я использую LinkedHashmap для копирования отсортированных записей в HashMap, я получаю желаемый результат (что было естественным, но это не главное. Последует порядок ключей HashMap)

    HashMap<Integer, String> sortedMap = new LinkedHashMap<>();

    for (Map.Entry<Integer, String> entry : entries) {
        System.out.println("Putting key:"+entry.getKey());
        sortedMap.put(entry.getKey(), entry.getValue());
    }

    System.out.println("Map after sorting:");

    showMap(sortedMap);

Выход:

Sorting by keys : 
Putting key:6
Putting key:12
Putting key:22
Putting key:55
Putting key:66
Putting key:77
Map after sorting:
[Key: 6 , Value: Rocky] 
[Key: 12 , Value: George] 
[Key: 22 , Value: Apple] 
[Key: 55 , Value: John] 
[Key: 66 , Value: Earl] 
[Key: 77 , Value: Pearl] 

Вы также можете сохранить экземпляр SET, возвращаемый методом Keyset (), и можете использовать этот экземпляр, когда вам нужен один и тот же заказ.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top