нет необходимости кодировать имя файла (по крайней мере, не для 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
Инициализатор экземпляра в данном случае просто синтаксический сахар, верно? Я не понимаю, зачем вам нужен дополнительный анонимный класс только для инициализации. И это не сработает, если создаваемый класс будет окончательным.
Вы также можете создать неизменную карту, используя статический инициализатор:
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);
}
}
Если вам нужно добавить только одно значение на карту, вы можете использовать Collections.singletonMap :
Map<K, V> map = Collections.singletonMap(key, value)
Я прочитал ответы и решил написать свой собственный конструктор карт. Не стесняйтесь копировать-вставлять и наслаждаться.
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
, что делает его более подходящим для статического импорта.
Я сделал что-то немного другое. Не самый лучший, но у меня это работает. Может быть, это может быть «обобщено».
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;
}
Примечание. Этот ответ на самом деле относится к вопросу Как напрямую инициализировать 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}
Вы можете использовать StickyMap
и MapEntry
из Cactoos :
private static final Map<String, String> MAP = new StickyMap<>(
new MapEntry<>("name", "Jeffrey"),
new MapEntry<>("age", "35")
);
В Java 9:
private static final Map<Integer, String> MY_MAP = Map.of(1, "one", 2, "two");
См. JEP 269 для деталей. JDK 9 достиг общедоступности в сентябре 2017 года.
С 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
С 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
Если вы хотите неизменяемую карту, наконец, java 9 добавил классный фабричный метод of
в интерфейс Map
. Аналогичный метод добавлен и в Set, List.
Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");
Если вам нужно что-то лаконичное и относительно безопасное, вы можете просто перенести проверку типов во время компиляции на время выполнения:
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);
}
}
}
Может быть, интересно проверить Google Collections , например, видео, которые они имеют на своей странице. Они предоставляют различные способы инициализации карт и наборов, а также предоставляют неизменные коллекции.
Обновление: теперь эта библиотека называется Гуава .
Мне нравится синтаксис анонимного класса; это - просто меньше кода. Однако один главный довод "против", который я нашел, - то, что Вы не сможете сериализировать тот объект через дистанционную работу. Вы получите исключение о неспособности найти анонимный класс на удаленной стороне.
Второй метод мог вызвать защищенные методы в случае необходимости. Это может быть полезно для инициализации классов, которые неизменны после конструкции.
Я использовал бы:
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);
}
}
Я никогда не создавал бы анонимный подкласс в этой ситуации. Статические инициализаторы работают одинаково хорошо, если требуется сделать карту немодифицируемой, например:
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);
}
Анонимный класс Вы создаете работы хорошо. Однако необходимо знать, что это внутреннее класс и как таковой, он будет содержать ссылку на окружающий экземпляр класса. Таким образом, Вы найдете, что не можете сделать определенных вещей с ним (использование XStream для одного). Вы получите некоторые очень странные ошибки.
Однако пока Вы знаете затем, этот подход прекрасен. Я использую его большую часть времени для инициализации всех видов наборов кратким способом.
РЕДАКТИРОВАНИЕ: Указанный правильно в комментариях, что это - статический класс. Очевидно, я не считал это достаточно тесно. Однако мои комментарии делают , все еще относятся к анонимным внутренним классам.
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!
Java 5 предоставляет этот более компактный синтаксис:
static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
put("Up", "Down");
put("Charm", "Strange");
put("Top", "Bottom");
}};
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 для констант, иначе он не может считаться константой.