Насколько неэффективным является передача collections.ulifainafine* экземпляр, который уже обернут collections.unmodifaine*?

StackOverflow https://stackoverflow.com/questions/4127921

Вопрос

У меня есть кусочки сделки, выполняемые различными пользовательскими (исходным кодом, недоступными) структурами, которые передают экземпляры карты. К сожалению, эти рамки не являются последовательными в их возвратных экземплярах карты, которые были обернуты с помощью коллекций. Unmodifiablemap. Чтобы обеспечить более высокую степень неизменности (для более легкого многопоточного использования) в моем коде, я просто одинаково назвал Collections.Unmodifiablemap на все, что возвращается этими структурами.

Map<String, Record> immutableMap = framework.getRecordsByName();
//does this created a nested set of unmodifiableMap wrapper instances?
this.immutableField = Collections.unmodifiableMap(immutableMap);
.
.
.
Map<String, Record> maybeImmutableMap = framework.getRecordsByName();
//is there some means to get instanceof to work?
if (!(maybeImmutableMap instanceof Collections.UnmodifiableMap))
{
    this.immutableField = Collections.unmodifiableMap(maybeImmutableMap);
}

Я понял, что у меня может быть проблема с производительностью вокруг этой части моего дизайна. И что в некоторых случаях я звонил в Collections.Unmodifiablemap, передавая его экземпляр, который уже был завернут рамками тем же вызовом. И что моя повторная обрезка, вероятно, вызывает дополнительный вызов метода по всему экземпляру.

Похоже, что использование «экземпляра collections.unmodifiablemap» не работает. И я не могу найти какого -либо способа обнаружить (исключая использование отражения, которое не является вариантом в этой ситуации - слишком медленно), если экземпляр карты, на который я в настоящее время ссылаюсь, должен быть обернут или нет.

Вопросы:

    А) Проверяет ли метод collections.unmodifiablemap (), чтобы увидеть, был ли он прошел экземпляр unmodifiablemap, и если это так, просто верните ту же ссылку (тем самым избегая необходимости проверять перед вызовом метода)?
    Б) Чтобы активно избегать получения исключений модификации, есть ли способ запросить экземпляр карты (кроме использования отражения), чтобы определить, изменяется ли он (или неизменен)?
    C) Если ответ на a - это нет, то есть ли какая -то эффективность в JVM/горячей точке, которая устраняет накладные расходы на вызов через многократный метод хмеля, чтобы добраться до экземпляра CORE?
Это было полезно?

Решение 4

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

И из -за соображений, связанных с множественными загрузчиками классов и сериализацией через RMI, одно решение, которое мне действительно понравилось (справочное сравнение класса от Jorn Horstmann), есть проблемы. Однако, когда я использую его подход и объединяю его с модификацией подхода к имени класса (рекомендованный Юджином Кулешовом), я думаю, что я приближаюсь, как я собираюсь получить решение, которое поможет мне в моем многопоточном Распределенная среда обработки. И это немного похоже на это:

public class MyCollections {
    private static final String UNMODIFIABLE_MAP_CLASS_NAME =
        Collections.unmodifiableMap(new HashMap()).getClass().getName();

    public static <K, V> Map<K, V> unmodifiableMap(Map<K, V> map) {
        return map.getClass().getName().equals(UNMODIFIABLE_MAP_CLASS_NAME)
                 ? map
                 : Collections.unmodifiableMap(map);
    }
}

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

Есть ли что -нибудь, что я забыл или не хватает в этом подходе?

И еще раз спасибо, всем, за ваш отзыв. Я очень ценю это.

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

Насколько мне известно:

  • А) Нет.
  • Б) Нет.
  • В) Нет.

ГуаваS. Immutable* Коллекции не имеют этой проблемы. Если ImmutableList.copyOf(list) вызывается с list это сам ImmutableList, сам аргумент возвращается. Кроме того, вы можете называть их (и проверить с instanceof для Immutable* Тип, а не интерфейс, что позволяет легко узнать, есть ли у вас неизменное экземпляр или нет. Таким образом, один из вариантов - скопировать результаты из структуры в эти неизменные коллекции и использовать их в вашем собственном коде. (У них также есть преимущество в том, что они действительно неизменные ... немодиажируемые обертки позволяют исходному изменчивому экземпляру, который они обертывают себя, если что -то имеет ссылку на него.)

Все это сказано, я бы не стал слишком беспокоиться о возможных накладных расходах на передачу метода вызовов через 1 или 2 немодиажируемые слои обертки, если вы не собираетесь каким -то образом обернуть их снова и снова. Как отмечали другие, крайне маловероятно, что из -за этого вы когда -либо заметите проблему с производительностью.

Вам не нужно беспокоиться о производительности, когда вы оберните одну немодиальную карту в другую. Посмотри на UnmodifiableMap класс:

private static class UnmodifiableMap<K,V> implements Map<K,V>, Serializable {
    ...
UnmodifiableMap(Map<? extends K, ? extends V> m) {
        if (m==null)
            throw new NullPointerException();
        this.m = m;
    }

public int size()                {return m.size();}
    ...
public V put(K key, V value) {
    throw new UnsupportedOperationException();
    }
public V remove(Object key) {
    throw new UnsupportedOperationException();
    }

public Set<K> keySet() {
    if (keySet==null)
    keySet = unmodifiableSet(m.keySet());
    return keySet;
}

public Set<Map.Entry<K,V>> entrySet() {
    if (entrySet==null)
    entrySet = new UnmodifiableEntrySet<K,V>(m.entrySet());
    return entrySet;
}
    ...

Вы можете видеть, что этот класс - только тонкая обертка вокруг настоящей карты. Все методы, как getSize, isEmpty и другие методы, которые не влияют на состояние карты, делегированы в экземпляр обернутой карты. Другие методы, которые влияют на состояние карты (put, remove) просто брось UnsupportedOperationException Так что существует почти нулевая перегрузка производительности.

Мои мысли о (C) заключаются в том, что компилятор горячей точки должен быть довольно хорош в внедрении небольших методов, которые просто возвращают результат другого вызова метода. Но я сомневаюсь, что это может видеть через несколько уровней корабли, например, хэшмап, завернутый в несколько немодифиаблемы. Я также не думаю, что это была бы преждевременная оптимизация, если вы знаете, что ваша библиотека иногда возвращает немодиальные карты. Почему бы не создать свою собственную обертку для Collections.Unmodifiablemap, как это (непроверенная, и я просто заметил, что простой экземпляр не будет работать, так как Impl в коллекциях является частным):

public class MyCollections {
    private static final Class UNMODIFIABLE_MAP_CLASS = Collections.unmodifiableMap(new HashMap()).getClass();

    public static <K, V> Map<K, V> unmodifiableMap(Map<K, V> map) {
        return map.getClass() == UNMODIFIABLE_MAP_CLASS ? map : Collections.unmodifiableMap(map);
    }
}

А) Нет

Б) нет

В), возможно, но я ожидаю, что это будет зависеть от имплантации JVM.

Декоратор, о котором идет речь, является чрезвычайно легким весом, существует ли конкретная причина, по которой дополнительный метод вызов, который просто делает другой вызов метода, вызовет некоторые проблемы с производительностью в вашей среде? Это не должно быть проблемой в каком -либо стандартном приложении, поэтому, если у вас нет действительно специального приложения/среды (интенсивное, мобильное устройство в реальном времени, в реальном времени ...) это не должно быть проблемой.

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

Но если вы действительно хотите проверить, не подлетай того, вы можете проверить «unmodifiablemap». Equals (class.getSimplename ())

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