Как я могу инициализировать статическую карту? - PullRequest
1032 голосов
/ 03 февраля 2009

Как бы вы инициализировали статический Map в Java?

Метод первый: статический инициализатор
Способ второй: инициализатор экземпляра (анонимный подкласс) или же какой-то другой метод?

Каковы плюсы и минусы каждого?

Вот пример, иллюстрирующий два метода:

import java.util.HashMap;
import java.util.Map;

public class Test {
    private static final Map<Integer, String> myMap = new HashMap<Integer, String>();
    static {
        myMap.put(1, "one");
        myMap.put(2, "two");
    }

    private static final Map<Integer, String> myMap2 = new HashMap<Integer, String>(){
        {
            put(1, "one");
            put(2, "two");
        }
    };
}

Ответы [ 41 ]

0 голосов
/ 03 февраля 2009

Мне нравится синтаксис анонимного класса; это просто меньше кода. Тем не менее, я обнаружил, что вы не сможете сериализовать этот объект с помощью удаленного взаимодействия. Вы получите исключение из-за невозможности найти анонимный класс на удаленной стороне.

0 голосов
/ 13 января 2014

Если вы можете использовать строковое представление ваших данных, эта опция также доступна в Java 8:

static Map<Integer, String> MAP = Stream.of(
        "1=one",
        "2=two"
).collect(Collectors.toMap(k -> Integer.parseInt(k.split("=")[0]), v -> v.split("=")[1]));
0 голосов
/ 16 апреля 2014

Теперь, когда Java 8 вышла, этот вопрос требует повторного рассмотрения. Я попробовал - похоже, что вы можете использовать синтаксис лямбда-выражений, чтобы получить довольно красивый и лаконичный (но безопасный для типов) буквальный синтаксис карты, который выглядит так:

        Map<String,Object> myMap = hashMap(
                bob -> 5,
                TheGimp -> 8,
                incredibleKoolAid -> "James Taylor",
                heyArnold -> new Date()
        );

        Map<String,Integer> typesafeMap = treeMap(
                a -> 5,
                bee -> 8,
                sea -> 13
                deep -> 21
        );

Не проверенный пример кода на https://gist.github.com/galdosd/10823529 Было бы любопытно мнение других по этому поводу (это слегка зло ...)

0 голосов
/ 30 ноября 2016

Даже с хорошим классом Gumm ImmutableMap иногда я хотел бы свободно создавать изменяемую карту. Я обнаружил, что хочу избежать статических блоков и анонимных подтипов, когда появилась Java 8, я написал крошечную библиотеку для помощи под названием Свободно .

.
// simple usage, assuming someMap is a Map<String, String> already declared
Map<String, String> example = new Fluent.HashMap<String, String>()
    .append("key1", "val1")
    .append("key2", "val2")
    .appendAll(someMap);

С настройками интерфейса Java 8 по умолчанию я мог бы реализовать методы Fluent.Map для всех стандартных реализаций Java Map (т.е. HashMap, ConcurrentSkipListMap и т. Д.) Без утомительного повторения.

Не изменяемые карты тоже просты.

Map<String, Integer> immutable = new Fluent.LinkedHashMap<String, Integer>()
    .append("one", 1)
    .append("two", 2)
    .append("three", 3)
    .unmodifiable();

См. https://github.com/alexheretic/fluent для источника, документации и примеров.

0 голосов
/ 29 ноября 2016

Вот код AbacusUtil

Map<Integer, String> map = N.asMap(1, "one", 2, "two");
// Or for Immutable map 
ImmutableMap<Integer, String> = ImmutableMap.of(1, "one", 2, "two");

Декларация: я разработчик AbacusUtil.

0 голосов
/ 03 февраля 2009

Второй метод может вызывать защищенные методы, если это необходимо. Это может быть полезно для инициализации классов, которые являются неизменяемыми после построения.

0 голосов
/ 29 января 2015

Мне нравится использовать «технику» статического инициализатора, когда у меня есть конкретная реализация абстрактного класса, который определил инициализирующий конструктор, но не имеет конструктора по умолчанию, но я хочу, чтобы у моего подкласса был конструктор по умолчанию.

Например:

public abstract class Shape {

    public static final String COLOR_KEY = "color_key";
    public static final String OPAQUE_KEY = "opaque_key";

    private final String color;
    private final Boolean opaque;

    /**
     * Initializing constructor - note no default constructor.
     *
     * @param properties a collection of Shape properties
     */
    public Shape(Map<String, Object> properties) {
        color = ((String) properties.getOrDefault(COLOR_KEY, "black"));
        opaque = (Boolean) properties.getOrDefault(OPAQUE_KEY, false);
    }

    /**
     * Color property accessor method.
     *
     * @return the color of this Shape
     */
    public String getColor() {
        return color;
    }

    /**
     * Opaque property accessor method.
     *
     * @return true if this Shape is opaque, false otherwise
     */
    public Boolean isOpaque() {
        return opaque;
    }
}

и моя конкретная реализация этого класса - но он хочет / нуждается в конструкторе по умолчанию:

public class SquareShapeImpl extends Shape {

    private static final Map<String, Object> DEFAULT_PROPS = new HashMap<>();

    static {
        DEFAULT_PROPS.put(Shape.COLOR_KEY, "yellow");
        DEFAULT_PROPS.put(Shape.OPAQUE_KEY, false);
    }

    /**
     * Default constructor -- intializes this square to be a translucent yellow
     */
    public SquareShapeImpl() {
        // the static initializer was useful here because the call to 
        // this(...) must be the first statement in this constructor
        // i.e., we can't be mucking around and creating a map here
        this(DEFAULT_PROPS);
    }

    /**
     * Initializing constructor -- create a Square with the given
     * collection of properties.
     *
     * @param props a collection of properties for this SquareShapeImpl
     */
    public SquareShapeImpl(Map<String, Object> props) {
        super(props);
    }
}

затем, чтобы использовать этот конструктор по умолчанию, мы просто делаем:

public class StaticInitDemo {

    public static void main(String[] args) {

        // create a translucent, yellow square...
        Shape defaultSquare = new SquareShapeImpl();

        // etc...
    }
}
0 голосов
/ 06 августа 2015

В Java 8 процедурный подход также может быть включен в Supplier:

Map<String,String> m = ((Supplier<Map<String,String>>)(() -> {
    Map<String,String> result = new HashMap<>();
    result.put("foo","hoo");
    ...
    return result;
)).get();

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

0 голосов
/ 28 января 2016

Здесь есть несколько хороших ответов, но я хочу предложить еще один.

Создайте свой собственный статический метод для создания и инициализации Map. У меня есть свой собственный класс CollectionUtils в пакете, который я использую в проектах с различными утилитами, которые я регулярно использую, и которые мне легко писать и которые не требуют зависимости от какой-то более крупной библиотеки.

Вот мой newMap метод:

public class CollectionUtils {
    public static Map newMap(Object... keyValuePairs) {
        Map map = new HashMap();
        if ( keyValuePairs.length % 2 == 1 ) throw new IllegalArgumentException("Must have even number of arguments");
        for ( int i=0; i<keyValuePairs.length; i+=2 ) {
            map.put(keyValuePairs[i], keyValuePairs[i + 1]);
        }
        return map;
    }
}

Использование:

import static CollectionUtils.newMap;
// ...
Map aMap = newMap("key1", 1.23, "key2", 2.34);
Map bMap = newMap(objKey1, objVal1, objKey2, objVal2, objKey3, objVal3);
// etc...

В нем не используются универсальные шаблоны, но вы можете ввести карту по своему усмотрению (просто убедитесь, что вы правильно ее ввели!)

Map<String,Double> aMap = (Map<String,Double>)newMap("key1", 1.23, "key2", 2.34);
0 голосов
/ 11 сентября 2018

Примечание. Этот ответ фактически относится к вопросу Как напрямую инициализировать HashMap (в буквальном смысле)? , но поскольку он помечен как [дубликат] этого ...


До Java 9 с Map.of () (который также ограничен 10 отображениями) вы можете расширить реализацию Map по вашему выбору, например ::10000 *

public class InitHashMap<K, V> extends HashMap<K, V>

повторно реализовать конструкторы HashMap:

public InitHashMap() {
    super();
}

public InitHashMap( int initialCapacity, float loadFactor ) {
    super( initialCapacity, loadFactor );
}

public InitHashMap( int initialCapacity ) {
    super( initialCapacity );
}

public InitHashMap( Map<? extends K, ? extends V> m ) {
    super( m );
}

и добавьте дополнительный конструктор, основанный на ответе Aerthel , но общий с использованием типов Object... и <K, V>:

public InitHashMap( final Object... keyValuePairs ) {

    if ( keyValuePairs.length % 2 != 0 )
        throw new IllegalArgumentException( "Uneven number of arguments." );

    K key = null;
    int i = -1;

    for ( final Object keyOrValue : keyValuePairs )
        switch ( ++i % 2 ) {
            case 0:  // key
                if ( keyOrValue == null )
                    throw new IllegalArgumentException( "Key[" + (i >> 1) + "] is <null>." );
                key = (K) keyOrValue;
                continue;
            case 1:  // value
                put( key, (V) keyOrValue );
        }
}

Run

public static void main( final String[] args ) {

    final Map<Integer, String> map = new InitHashMap<>( 1, "First", 2, "Second", 3, "Third" );
    System.out.println( map );
}

выход

{1=First, 2=Second, 3=Third}

Вы также можете расширить интерфейс Map:

public interface InitMap<K, V> extends Map<K, V> {

    static <K, V> Map<K, V> of( final Object... keyValuePairs ) {

        if ( keyValuePairs.length % 2 != 0 )
            throw new IllegalArgumentException( "Uneven number of arguments." );

        final Map<K, V> map = new HashMap<>( keyValuePairs.length >> 1, .75f );
        K key = null;
        int i = -1;

        for ( final Object keyOrValue : keyValuePairs )
            switch ( ++i % 2 ) {
                case 0: // key
                    if ( keyOrValue == null )
                        throw new IllegalArgumentException( "Key[" + (i >> 1) + "] is <null>." );
                    key = (K) keyOrValue;
                    continue;
                case 1: // value
                    map.put( key, (V) keyOrValue );
            }
        return map;
    }
}

Run

public static void main( final String[] args ) {

    System.out.println( InitMap.of( 1, "First", 2, "Second", 3, "Third" ) );
}

выход

{1=First, 2=Second, 3=Third}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...