2017-02-11 6 views
4

Я готовлюсь к экзамену по Java и задаю один вопрос, который заставил меня много времени. Несмотря на то, что я изучаю это трудно, я не могу определить, что определяет порядок результата.Java 8 - Collections.groupingBy result order

Посмотрите, пожалуйста:

class Country { 

    public enum Continent { 
     ASIA, EUROPE 
    } 
    String name; 
    Continent region; 

    public Country(String na, Continent reg) { 
     name = na; 
     region = reg; 
    } 

    public String getName() { 
     return name; 
    } 

    public Continent getRegion() { 
     return region; 
    } 
} 

public class OrderQuestion { 

    public static void main(String[] args) { 
     List<Country> couList = Arrays.asList(
       new Country("Japan", Country.Continent.ASIA), 
       new Country("Italy", Country.Continent.EUROPE), 
       new Country("Germany", Country.Continent.EUROPE)); 
     Map<Country.Continent, List<String>> regionNames = couList.stream() 
       .collect(Collectors.groupingBy(Country::getRegion, 
         Collectors.mapping(Country::getName, Collectors.toList()))); 
     System.out.println(regionNames); 
    } 
} 

Каков результат?

A. {EUROPE = [Italy, Germany], ASIA = [Japan]}
B. {ASIA = [Japan], EUROPE = [Italy, Germany]}
C. {EUROPE = [Germany, Italy], ASIA = [Japan]}
D. {EUROPE = [Germany], EUROPE = [Italy], ASIA = [Japan]}

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

+3

Посмотрите на документацию API для «Карты» и посмотрите, что он говорит о порядке элементов https://docs.oracle.com/javase/8/docs/api/java/util/Map.html – SpiderPig

+0

Предлагаемые ответы являются: A. {EUROPE = [Италия, Германия], ASIA = [Япония]} B. {ASIA = [Япония], EUROPE = [Италия, Германия]} C. {EUROPE = [Германия, Италия] , ASIA = [Япония]} D. {EUROPE = [Германия], EUROPE = [Италия], ASIA = [Япония]} Я знаю, что создает Java Runtime, выполняющий этот код (A), но понятия не имею, почему это и не что-то другое. Я ищу обоснование. –

+0

Используя потоки, вы можете выполнять множество операций в одной строке кода. Чтобы сделать вопрос более понятным, вы можете разделить линию потока, назначить каждый шаг переменной и описать, что именно вас удивляет и что вы, кроме как видите. – KernelMode

ответ

6

Мы можем устранить D, потому что ключи на карте должны быть уникальными, что не подходит для EUROPE.

Мы можем устранить C по заказу в [Germany, Italy]. Italy был размещен до Germany в списке, поэтому его также необходимо сохранить в этом порядке в списке результатов.

Но как мы должны решить, следует ли устранить B или A? Ну, мы не можем.

Карта не гарантирует определенный порядок пар ключ-значение. Некоторые карты позволяют запомнить порядок размещения пар ключ-значение, таких как LinkedHashMap, некоторые позволяют заказывать записи с помощью таких ключей, как TreeMap, но это поведение не указано для Collectors.groupingBy.

Это подтверждается фактом, что этот метод использует HashMap, который заказывает пары ключ-значение на основе hashCode() ключа (Country.Continent перечисление здесь) и количество пар, уже проведенных. Реализация hashCode() для Enum наследуется от класса Object, что означает, что он основан на местоположении памяти, которое может меняться каждый раз при запуске JVM, поэтому это случайное значение, которое мешает нам принимать какой-либо заказ (который подтверждает, что он не указан).

Таким образом, основываясь на недостатке спецификации о карте, возвращаемой groupingBy, возможны оба заказа, поэтому оба варианта A и B являются возможными.

+4

Хороший анализ, +1 , По моему мнению, вопрос, описанный ОП, является плохим экзаменационным вопросом. Получение «правильного» ответа зависит от поведения, специфичного для реализации (упорядочение HashMap), а не для спецификации. –

+0

Pshemo, благодарю вас за анализ, но: a) Вопрос предполагает только правильный ответ b) Почему изменение порядка записей в couList влияет на результат? HashMap по определению не гарантирует какого-либо определенного порядка, но на практике порядок определяется hashCode (?). Например, несмотря на модификацию порядка записей для следующего результата: \t Map hm = new HashMap <>(); \t hm.put (0, "a"); \t hm.put (1, "b"); \t \t \t hm.put (2, "c"); \t hm.forEach ((k, v) -> out.println (k + ":" + v)); \t что: 0: а 1: б 2: с –

+1

@FredFilozof (а) Я подозреваю, что автор этого вопроса просто запустить его код несколько раз и получил тот же ответ, чтобы он предположил, что это должно быть правильным всегда. Но мне удалось получить оба ответа, создав дополнительные объекты до того, как enum был использован, поэтому они будут занимать разную память, а затем предварительно предоставлены, так что их хэш также случается. (b) порядок элементов в вашем потоке здесь зависит от порядка элементов в источнике (в 'couList'). Это правда, что HashMap не гарантирует какой-либо определенный порядок, но есть * некоторый * порядок на основе хэш-кодов ключей и количества пар. – Pshemo

 Смежные вопросы

  • Нет связанных вопросов^_^