Как я могу инициализировать статическую карту?

нет необходимости кодировать имя файла (по крайней мере, не для linux). Этот код работает на моей Linux-системе:

use warnings;
use strict;

#   Text is stored in utf8 within *this* file.
use utf8;

my $with_smiley = $ARGV[0] || 0;

my $filename = 'äöü' .
  ($with_smiley ? '?' : '' ).
     '.txt';

open my $fh, '>', $filename or die "open: $!";

binmode $fh, ':utf8';

print $fh "Filename: $filename\n";

close $fh;

HTH, Paul

1046
задан Gerold Broser 11 September 2018 в 01:12
поделиться

20 ответов

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

Вы также можете создать неизменную карту, используя статический инициализатор:

public class Test {
    private static final Map<Integer, String> myMap;
    static {
        Map<Integer, String> aMap = ....;
        aMap.put(1, "one");
        aMap.put(2, "two");
        myMap = Collections.unmodifiableMap(aMap);
    }
}
1046
ответ дан 6 revs, 5 users 85% 11 September 2018 в 01:12
поделиться

Если вам нужно добавить только одно значение на карту, вы можете использовать Collections.singletonMap :

Map<K, V> map = Collections.singletonMap(key, value)
3
ответ дан Stromata 11 September 2018 в 01:12
поделиться

Я прочитал ответы и решил написать свой собственный конструктор карт. Не стесняйтесь копировать-вставлять и наслаждаться.

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

/**
 * A tool for easy creation of a map. Code example:<br/>
 * {@code MapBuilder.of("name", "Forrest").and("surname", "Gump").build()}
 * @param <K> key type (inferred by constructor)
 * @param <V> value type (inferred by constructor)
 * @author Vlasec (for http://stackoverflow.com/a/30345279/1977151)
 */
public class MapBuilder <K, V> {
    private Map<K, V> map = new HashMap<>();

    /** Constructor that also enters the first entry. */
    private MapBuilder(K key, V value) {
        and(key, value);
    }

    /** Factory method that creates the builder and enters the first entry. */
    public static <A, B> MapBuilder<A, B> mapOf(A key, B value) {
        return new MapBuilder<>(key, value);
    }

    /** Puts the key-value pair to the map and returns itself for method chaining */
    public MapBuilder<K, V> and(K key, V value) {
        map.put(key, value);
        return this;
    }

    /**
     * If no reference to builder is kept and both the key and value types are immutable,
     * the resulting map is immutable.
     * @return contents of MapBuilder as an unmodifiable map.
     */
    public Map<K, V> build() {
        return Collections.unmodifiableMap(map);
    }
}

РЕДАКТИРОВАТЬ: В последнее время я все чаще нахожу публичный статический метод of, и мне это нравится. Я добавил его в код и сделал конструктор приватным, переключившись на статический шаблон фабричного метода.

EDIT2: Еще недавно мне больше не нравился статический метод, называемый of, так как он выглядит довольно плохо при использовании статического импорта. Вместо этого я переименовал его в mapOf, что делает его более подходящим для статического импорта.

2
ответ дан Vlasec 11 September 2018 в 01:12
поделиться

Я сделал что-то немного другое. Не самый лучший, но у меня это работает. Может быть, это может быть «обобщено».

private static final Object[][] ENTRIES =
{
  {new Integer(1), "one"},
  {new Integer(2), "two"},
};
private static final Map myMap = newMap(ENTRIES);

private static Map newMap(Object[][] entries)
{
  Map map = new HashMap();

  for (int x = 0; x < entries.length; x++)
  {
    Object[] entry = entries[x];

    map.put(entry[0], entry[1]);
  }

  return map;
}
0
ответ дан Gary Kephart 11 September 2018 в 01:12
поделиться

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


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

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 );
        }
}

Выполнить

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;
    }
}

Выполнить

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

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

Выход

{1=First, 2=Second, 3=Third}
0
ответ дан Gerold Broser 11 September 2018 в 01:12
поделиться

Вы можете использовать StickyMap и MapEntry из Cactoos :

private static final Map<String, String> MAP = new StickyMap<>(
  new MapEntry<>("name", "Jeffrey"),
  new MapEntry<>("age", "35")
);
4
ответ дан yegor256 11 September 2018 в 01:12
поделиться

В Java 9: ​​

private static final Map<Integer, String> MY_MAP = Map.of(1, "one", 2, "two");

См. JEP 269 для деталей. JDK 9 достиг общедоступности в сентябре 2017 года.

48
ответ дан Jonik 11 September 2018 в 01:12
поделиться

С Java 8 я стал использовать следующий шаблон:

private static final Map<String, Integer> MAP = Stream.of(
    new AbstractMap.SimpleImmutableEntry<>("key1", 1),
    new AbstractMap.SimpleImmutableEntry<>("key2", 2)
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Это не самый лаконичный и немного обходной путь, но

  • он не требует все, что находится за пределами java.util
  • , является безопасным и легко приспосабливается к различным типам ключей и значений.
4
ответ дан zrvan 11 September 2018 в 01:12
поделиться

С Eclipse Collections , все следующие будут работать:

import java.util.Map;

import org.eclipse.collections.api.map.ImmutableMap;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.impl.factory.Maps;

public class StaticMapsTest
{
    private static final Map<Integer, String> MAP =
        Maps.mutable.with(1, "one", 2, "two");

    private static final MutableMap<Integer, String> MUTABLE_MAP =
       Maps.mutable.with(1, "one", 2, "two");


    private static final MutableMap<Integer, String> UNMODIFIABLE_MAP =
        Maps.mutable.with(1, "one", 2, "two").asUnmodifiable();


    private static final MutableMap<Integer, String> SYNCHRONIZED_MAP =
        Maps.mutable.with(1, "one", 2, "two").asSynchronized();


    private static final ImmutableMap<Integer, String> IMMUTABLE_MAP =
        Maps.mutable.with(1, "one", 2, "two").toImmutable();


    private static final ImmutableMap<Integer, String> IMMUTABLE_MAP2 =
        Maps.immutable.with(1, "one", 2, "two");
}

Вы также можете статически инициализировать карты примитивов с Eclipse Collections.

import org.eclipse.collections.api.map.primitive.ImmutableIntObjectMap;
import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
import org.eclipse.collections.impl.factory.primitive.IntObjectMaps;

public class StaticPrimitiveMapsTest
{
    private static final MutableIntObjectMap<String> MUTABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two");

    private static final MutableIntObjectMap<String> UNMODIFIABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .asUnmodifiable();

    private static final MutableIntObjectMap<String> SYNCHRONIZED_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .asSynchronized();

    private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .toImmutable();

    private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP2 =
            IntObjectMaps.immutable.<String>empty()
                    .newWithKeyValue(1, "one")
                    .newWithKeyValue(2, "two");
} 

Примечание: Я коммиттер Eclipse Collections

31
ответ дан Donald Raab 11 September 2018 в 01:12
поделиться

Если вы хотите неизменяемую карту, наконец, java 9 добавил классный фабричный метод of в интерфейс Map. Аналогичный метод добавлен и в Set, List.

Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");

7
ответ дан Bharanidharan K 11 September 2018 в 01:12
поделиться

Если вам нужно что-то лаконичное и относительно безопасное, вы можете просто перенести проверку типов во время компиляции на время выполнения:

static final Map<String, Integer> map = MapUtils.unmodifiableMap(
    String.class, Integer.class,
    "cat",  4,
    "dog",  2,
    "frog", 17
);

Эта реализация должна отлавливать любые ошибки:

import java.util.HashMap;

public abstract class MapUtils
{
    private MapUtils() { }

    public static <K, V> HashMap<K, V> unmodifiableMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        return Collections.<K, V>unmodifiableMap(makeMap(
            keyClazz,
            valClazz,
            keyValues));
    }

    public static <K, V> HashMap<K, V> makeMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        if (keyValues.length % 2 != 0)
        {
            throw new IllegalArgumentException(
                    "'keyValues' was formatted incorrectly!  "
                  + "(Expected an even length, but found '" + keyValues.length + "')");
        }

        HashMap<K, V> result = new HashMap<K, V>(keyValues.length / 2);

        for (int i = 0; i < keyValues.length;)
        {
            K key = cast(keyClazz, keyValues[i], i);
            ++i;
            V val = cast(valClazz, keyValues[i], i);
            ++i;
            result.put(key, val);
        }

        return result;
    }

    private static <T> T cast(Class<? extends T> clazz, Object object, int i)
    {
        try
        {
            return clazz.cast(object);
        }
        catch (ClassCastException e)
        {
            String objectName = (i % 2 == 0) ? "Key" : "Value";
            String format = "%s at index %d ('%s') wasn't assignable to type '%s'";
            throw new IllegalArgumentException(String.format(format, objectName, i, object.toString(), clazz.getSimpleName()), e);
        }
    }
}
5
ответ дан Philip 11 September 2018 в 01:12
поделиться

Может быть, интересно проверить Google Collections , например, видео, которые они имеют на своей странице. Они предоставляют различные способы инициализации карт и наборов, а также предоставляют неизменные коллекции.

Обновление: теперь эта библиотека называется Гуава .

18
ответ дан Paŭlo Ebermann 11 September 2018 в 01:12
поделиться

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

0
ответ дан Chase Seibert 11 September 2018 в 11:12
поделиться

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

0
ответ дан Mark Renouf 11 September 2018 в 11:12
поделиться

Я использовал бы:

public class Test {
    private static final Map<Integer, String> MY_MAP = createMap();

    private static Map<Integer, String> createMap() {
        Map<Integer, String> result = new HashMap<Integer, String>();
        result.put(1, "one");
        result.put(2, "two");
        return Collections.unmodifiableMap(result);
    }
}
  1. это избегает анонимного класса, который я лично считаю плохим стилем и избегаю
  2. , это делает создание карты более явным
  3. , это делает карту немодифицируемой
  4. , поскольку MY_MAP является постоянным, я назвал бы его как постоянный
174
ответ дан Peter Štibraný 11 September 2018 в 11:12
поделиться

Я никогда не создавал бы анонимный подкласс в этой ситуации. Статические инициализаторы работают одинаково хорошо, если требуется сделать карту немодифицируемой, например:

private static final Map<Integer, String> MY_MAP;
static
{
    Map<Integer, String>tempMap = new HashMap<Integer, String>();
    tempMap.put(1, "one");
    tempMap.put(2, "two");
    MY_MAP = Collections.unmodifiableMap(tempMap);
}
27
ответ дан eljenso 11 September 2018 в 11:12
поделиться
  • 1
    Привет, Jeff. Добро пожаловать в Переполнение стека. Вы могли отредактировать свой ответ для объяснения, почему плакат должен использовать код вместо кода, отправленного в вопросе (или какой-либо из ответов)? There' s много " noise" в Вашем ответе, имеющем дело с созданием и рисованием изображений к холсту, который не имеет никакого отношения к фактическому вопросу, который задают. Кроме того, так как этот вопрос стар и имеет принятый ответ, Ваш ответ должен объяснить что-то полезное, которое не объяснено в других ответах. – Scott Mermelstein 28 January 2014 в 06:20

Анонимный класс Вы создаете работы хорошо. Однако необходимо знать, что это внутреннее класс и как таковой, он будет содержать ссылку на окружающий экземпляр класса. Таким образом, Вы найдете, что не можете сделать определенных вещей с ним (использование XStream для одного). Вы получите некоторые очень странные ошибки.

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

РЕДАКТИРОВАНИЕ: Указанный правильно в комментариях, что это - статический класс. Очевидно, я не считал это достаточно тесно. Однако мои комментарии делают , все еще относятся к анонимным внутренним классам.

5
ответ дан Brian Agnew 11 September 2018 в 11:12
поделиться
  • 1
    Просто к вашему сведению, path.exists() был удержан от использования в более поздних версиях Узла. Теперь it' s fs.exists(). – MikeSchinkel 7 October 2012 в 16:01

Одно преимущество для второго метода состоит в том, что можно перенести его с Collections.unmodifiableMap(), чтобы гарантировать, что ничто не собирается обновить набор позже:

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

 // later on...

 CONSTANT_MAP.put(3, "three"); // going to throw an exception!
93
ответ дан Michael Lihs 11 September 2018 в 11:12
поделиться

Java 5 предоставляет этот более компактный синтаксис:

static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
    put("Up",    "Down");
    put("Charm", "Strange");
    put("Top",   "Bottom");
}};
177
ответ дан 19 December 2019 в 20:19
поделиться
public class Test {
    private static final Map<Integer, String> myMap;
    static {
        Map<Integer, String> aMap = ....;
        aMap.put(1, "one");
        aMap.put(2, "two");
        myMap = Collections.unmodifiableMap(aMap);
    }
}

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

public class Test {

    public static final Map numbers = Collections.unmodifiableMap(new HashMap(2, 1.0f){
        {
            put(1, "one");
            put(2, "two");
        }
    });
}

И предлагается использовать unmodifiableMap для констант, иначе он не может считаться константой.

12
ответ дан 19 December 2019 в 20:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: