이와 같이 Java HashMap을 초기화하는 방법이 있습니까?:
Map<String,String> test = new HashMap<String, String>{"test":"test","test":"test"};
올바른 구문은 무엇입니까? 나는 이것에 관해 아무것도 찾지 못했습니다. 이게 가능해? 저는 맵을 생성할 때 사전에 알려지고 변경되지 않는 "최종/정적" 값을 맵에 넣는 가장 짧고 빠른 방법을 찾고 있습니다.
질문자 :jens
이와 같이 Java HashMap을 초기화하는 방법이 있습니까?:
Map<String,String> test = new HashMap<String, String>{"test":"test","test":"test"};
올바른 구문은 무엇입니까? 나는 이것에 관해 아무것도 찾지 못했습니다. 이게 가능해? 저는 맵을 생성할 때 사전에 알려지고 변경되지 않는 "최종/정적" 값을 맵에 넣는 가장 짧고 빠른 방법을 찾고 있습니다.
단일 항목만 필요한 경우: Collections.singletonMap("key", "value")
있습니다.
예, 지금 가능합니다. Java 9에는 맵 생성을 단순화하는 몇 가지 팩토리 메소드가 추가되었습니다.
// this works for up to 10 elements: Map<String, String> test1 = Map.of( "a", "b", "c", "d" ); // this works for any number of elements: import static java.util.Map.entry; Map<String, String> test2 = Map.ofEntries( entry("a", "b"), entry("c", "d") );
위의 예에서 test
와 test2
는 맵을 표현하는 방법만 다를 뿐 동일합니다. Map.of
메서드는 맵에서 최대 10개의 요소에 대해 정의되지만 Map.ofEntries
메서드에는 이러한 제한이 없습니다.
이 경우 결과 맵은 변경할 수 없는 맵이 됩니다. 맵을 변경 가능하게 하려면 다음과 같이 다시 복사할 수 있습니다. 예를 들어 mutableMap = new HashMap<>(Map.of("a", "b"));
( JEP 269 및 Javadoc 참조 )
아니요, 모든 요소를 수동으로 추가해야 합니다. 익명 서브클래스에서 이니셜라이저를 사용하여 구문을 조금 더 짧게 만들 수 있습니다.
Map<String, String> myMap = new HashMap<String, String>() {{ put("a", "b"); put("c", "d"); }};
그러나 익명의 하위 클래스는 경우에 따라 원치 않는 동작을 유발할 수 있습니다. 여기에는 다음이 포함됩니다.
초기화를 위한 함수를 사용하면 초기화에서 맵을 생성할 수도 있지만 불쾌한 부작용을 피할 수 있습니다.
Map<String, String> myMap = createMap(); private static Map<String, String> createMap() { Map<String,String> myMap = new HashMap<String,String>(); myMap.put("a", "b"); myMap.put("c", "d"); return myMap; }
이것은 한 가지 방법입니다.
Map<String, String> h = new HashMap<String, String>() {{ put("a","b"); }};
그러나 위의 코드(HashMap에서 상속하는 새 클래스가 생성됨)를 이해하고 있는지 확인하고 주의해야 합니다. 따라서 http://www.c2.com/cgi/wiki?DoubleBraceInitialization 에서 더 많은 정보를 읽거나 단순히 Guava를 사용해야 합니다.
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
ImmutableMap.of
는 최대 5개의 항목에 대해 작동합니다. 그렇지 않으면 builder: source 를 사용하십시오.
타사 라이브러리를 허용하면 Guava 의 ImmutableMap 을 사용하여 문자 그대로의 간결함을 얻을 수 있습니다.
Map<String, String> test = ImmutableMap.of("k1", "v1", "k2", "v2");
이것은 최대 5개의 키/값 쌍에 대해 작동합니다. 그렇지 않으면 빌더를 사용할 수 있습니다.
Map<String, String> test = ImmutableMap.<String, String>builder() .put("k1", "v1") .put("k2", "v2") ... .build();
이를 수행하는 직접적인 방법은 없습니다. Java에는 Map 리터럴이 없습니다(아직 - Java 8용으로 제안된 것 같습니다).
어떤 사람들은 다음을 좋아합니다.
Map<String,String> test = new HashMap<String, String>(){{ put("test","test"); put("test","test");}};
이렇게 하면 인스턴스 이니셜라이저가 이러한 값을 저장하는 HashMap의 익명 하위 클래스가 생성됩니다. (그런데 맵에는 동일한 값이 두 번 포함될 수 없습니다. 두 번째 입력은 첫 번째 값을 덮어씁니다. 다음 예제에서는 다른 값을 사용하겠습니다.)
일반적인 방법은 다음과 같습니다(로컬 변수의 경우).
Map<String,String> test = new HashMap<String, String>(); test.put("test","test"); test.put("test1","test2");
test
맵이 인스턴스 변수인 경우 초기화를 생성자 또는 인스턴스 이니셜라이저에 넣습니다.
Map<String,String> test = new HashMap<String, String>(); { test.put("test","test"); test.put("test1","test2"); }
test
맵이 클래스 변수인 경우 초기화를 정적 이니셜라이저에 넣습니다.
static Map<String,String> test = new HashMap<String, String>(); static { test.put("test","test"); test.put("test1","test2"); }
지도가 절대 변경되지 않도록 하려면 초기화 후에 Collections.unmodifiableMap(...)
지도를 래핑해야 합니다. 정적 이니셜라이저에서도 이 작업을 수행할 수 있습니다.
static Map<String,String> test; { Map<String,String> temp = new HashMap<String, String>(); temp.put("test","test"); temp.put("test1","test2"); test = Collections.unmodifiableMap(temp); }
test
최종으로 만들 수 있는지 확실하지 않습니다... 시도해보고 여기에서 보고하세요.)
Map<String,String> test = new HashMap<String, String>() { { put(key1, value1); put(key2, value2); } };
일반 Java 7 클래스 및 varargs를 사용하는 대안: 다음 메서드를 HashMapBuilder
public static HashMap<String, String> build(String... data){ HashMap<String, String> result = new HashMap<String, String>(); if(data.length % 2 != 0) throw new IllegalArgumentException("Odd number of arguments"); String key = null; Integer step = -1; for(String value : data){ step++; switch(step % 2){ case 0: if(value == null) throw new IllegalArgumentException("Null key value"); key = value; continue; case 1: result.put(key, value); break; } } return result; }
다음과 같은 방법을 사용하십시오.
HashMap<String,String> data = HashMapBuilder.build("key1","value1","key2","value2");
자바 8
일반 Java 8에서는 Streams/Collectors
를 사용하여 작업을 수행할 수도 있습니다.
Map<String, String> myMap = Stream.of( new SimpleEntry<>("key1", "value1"), new SimpleEntry<>("key2", "value2"), new SimpleEntry<>("key3", "value3")) .collect(toMap(SimpleEntry::getKey, SimpleEntry::getValue));
이것은 Anonymous 클래스를 생성하지 않는다는 장점이 있습니다.
가져오기는 다음과 같습니다.
import static java.util.stream.Collectors.toMap; import java.util.AbstractMap.SimpleEntry;
물론 다른 답변에서 언급했듯이 Java 9 이상에서는 동일한 작업을 수행하는 더 간단한 방법이 있습니다.
Java 9 이상에서 Map.of…
메소드를 사용하십시오.
Map< String , String > animalSounds = Map.of( "dog" , "bark" , // key , value "cat" , "meow" , // key , value "bird" , "chirp" // key , value ) ;
Map.of
Java 9는 원하는 작업을 수행하기 위해 Map.of
정적 메소드를 추가했습니다. 리터럴 구문을 사용하여 변경할 수 없는 Map
맵(항목 모음)은 변경할 수 없으므로 인스턴스화한 후에 항목을 추가하거나 제거할 수 없습니다. 또한 각 항목의 키와 값은 변경할 수 없으며 변경할 수 없습니다. Javadoc을 참조 등 수없이 널 (NULL)와 같은 다른 규칙를 들어, 중복 키를 허용하지 않으며, 매핑의 반복 순서는 임의적이다.
요일 맵에 대한 몇 가지 샘플 데이터를 사용하여 해당 날짜에 일할 것으로 예상되는 사람에 대한 이러한 방법을 살펴보겠습니다.
Person alice = new Person( "Alice" ); Person bob = new Person( "Bob" ); Person carol = new Person( "Carol" );
Map.of()
Map.of
는 빈 Map
생성합니다. 수정할 수 없으므로 항목을 추가할 수 없습니다. 다음은 항목이 없는 비어 있는 이러한 맵의 예입니다.
Map < DayOfWeek, Person > dailyWorkerEmpty = Map.of();
DailyWorkerEmpty.toString(): {}
Map.of( … )
Map.of( k , v , k , v , …)
는 1~10개의 키-값 쌍을 사용하는 여러 메서드입니다. 다음은 두 항목의 예입니다.
Map < DayOfWeek, Person > weekendWorker = Map.of( DayOfWeek.SATURDAY , alice , // key , value DayOfWeek.SUNDAY , bob // key , value ) ;
주말 작업자.toString(): {SUNDAY=Person{ name='Bob' }, SATURDAY=Person{ name='Alice' }}
Map.ofEntries( … )
Map.ofEntries( Map.Entry , … )
Map.Entry
인터페이스를 구현하는 객체를 원하는 수만큼 받습니다. Java는 해당 인터페이스를 구현하는 두 개의 클래스를 번들로 제공합니다. 하나는 변경 가능하고 다른 하나는 변경할 수 없습니다. AbstractMap.SimpleEntry
, AbstractMap.SimpleImmutableEntry
. 그러나 구체적인 클래스를 지정할 필요는 없습니다. Map.entry( k , v )
메서드를 호출 Map.Entry
인터페이스를 구현하는 일부 클래스의 개체를 다시 얻을 수 있습니다.
Map < DayOfWeek, Person > weekdayWorker = Map.ofEntries( Map.entry( DayOfWeek.MONDAY , alice ) , // Call to `Map.entry` method returns an object implementing `Map.Entry`. Map.entry( DayOfWeek.TUESDAY , bob ) , Map.entry( DayOfWeek.WEDNESDAY , bob ) , Map.entry( DayOfWeek.THURSDAY , carol ) , Map.entry( DayOfWeek.FRIDAY , carol ) );
weekdayWorker.toString(): {WEDNESDAY=Person{ name='Bob' }, TUESDAY=Person{ name='Bob' }, THURSDAY=Person{ name='Carol' }, FRIDAY=Person{ name='Carol' } , MONDAY=사람{ name='앨리스' }}
Map.copyOf
Map.copyOf
메소드가 추가되었습니다. 기존 지도를 전달하고 해당 지도의 변경할 수 없는 복사본을 다시 가져옵니다.
Map.of
를 통해 생성된 맵의 반복자 순서는 보장 되지 않습니다. 항목에는 임의의 순서가 있습니다. 문서에서는 순서가 변경될 수 있다고 경고하므로 표시된 순서에 따라 코드를 작성하지 마십시오.
이 모든 Map.of…
메서드는 지정되지 않은 클래스 Map
을 반환합니다. 기본 구체 클래스는 Java 버전마다 다를 수도 있습니다. 이러한 익명성을 통해 Java는 특정 데이터에 가장 잘 맞는 다양한 구현 중에서 선택할 수 있습니다. 예를 들어 키가 enum 에서 온 경우 Java는 덮개 아래에서 EnumMap
사용할 수 있습니다.
변경할 수 없는 맵을 생성할 수 있는 SimpleEntry가 있는 AbstractMap 클래스를 사용할 수 있습니다.
Map<String, String> map5 = Stream.of( new AbstractMap.SimpleEntry<>("Sakshi","java"), new AbstractMap.SimpleEntry<>("fine","python") ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); System.out.println(map5.get("Sakshi")); map5.put("Shiva", "Javascript"); System.out.println(map5.get("Shiva"));// here we can add multiple entries.
2가지 쉬운 방법으로 자신만의 Map.of
(Java 9 이상에서만 사용 가능) 메서드를 쉽게 만들 수 있습니다.
예시
public <K,V> Map<K,V> mapOf(K k1, V v1, K k2, V v2 /* perhaps more parameters */) { return new HashMap<K, V>() {{ put(k1, v1); put(k2, v2); // etc... }}; }
특정 매개변수 집합에 대해 많은 메서드를 만드는 대신 목록을 사용하여 이를 만들 수도 있습니다.
예시
public <K, V> Map<K, V> mapOf(List<K> keys, List<V> values) { if(keys.size() != values.size()) { throw new IndexOutOfBoundsException("amount of keys and values is not equal"); } return new HashMap<K, V>() {{ IntStream.range(0, keys.size()).forEach(index -> put(keys.get(index), values.get(index))); }}; }
참고 이것을 사용할 때마다 익명 클래스를 만들기 때문에 모든 것에 이것을 사용하는 것은 권장하지 않습니다.
키-값 쌍을 하나만 배치해야 하는 경우 Collections.singletonMap(key, value);
Java 8 이하
정적 블록을 사용하여 일부 값으로 맵을 초기화할 수 있습니다. 예시 :
public static Map<String,String> test = new HashMap<String, String> static { test.put("test","test"); test.put("test1","test"); }
자바 9 이상
Map.of() 메서드를 사용하여 선언하는 동안 일부 값으로 맵을 초기화할 수 있습니다. 예시 :
public static Map<String,String> test = Map.of("test","test","test1","test");
다음 방법을 사용하여 해시맵을 초기화할 수 있습니다.
생성자를 사용한 HashMap
Map<문자열, 문자열> hashMap = new HashMap<문자열, 문자열>();
hashMap.put("hcl", "amit"); hashMap.put("tcs","ravi");
Hashmap에는 4개의 다른 유형 생성자가 있으므로 요구 사항에 따라 초기화할 수 있습니다. 이제 HashMap(int initialCapacity) 생성자를 사용합니다.
Map<String, String> hashMap = new HashMap<String, String>(3); hashMap.put("virat", "cricket"); hashMap.put("amit","football");
참고 : HashMap 생성 방법
컬렉션을 사용하는 싱글톤 HashMaps
Map<String, String> immutableMap = Collections.singletonMap("rohit", "cricket");
컬렉션을 사용하여 빈 HashMaps
Map<String, String> emptyMap = Collections.emptyMap();
HashMap을 생성하기 위한 익명의 서브클래스
Map<String, String> map = new HashMap<String, String>() {{ put("hcl", "amit"); put("tcs","ravi"); put("wipro","anmol"); }};
이를 수행하는 간단한 방법:
public static Map<String, String> mapWithValues(String...values) { Map<String, String> map = new HashMap<String, String>(); for (int x = 0; x < values.length; x = x+2) { map.put(values[x], values[x+1]); } return map; }
인스턴스 변수인 경우 인스턴스 초기화 블록이 확실히 올바른 방법입니다. 특히 다른 유형의 맵이 필요하기 때문에 Map.of()
그러나 기분이 좋지 않다면 Java 8 Supplier
사용할 수 있습니다(권장하지 않음).
private final Map<String,Runnable> games = ((Supplier<Map<String,Runnable>>)() -> { Map<String,Runnable> map = new LinkedHashMap<>(); map.put("solarus",this::playSolarus); map.put("lichess",this::playLichess); return map; }).get();
또는 자신만의 기능적 인터페이스를 만드십시오(저에게는 괜찮아 보입니다).
@FunctionalInterface public interface MapMaker<M> { static <M extends Map<K,V>,K,V> M make(M map,MapMaker<M> maker) { maker.build(map); return map; } void build(M map); } // Can use LinkedHashMap! private final Map<String,Runnable> games = MapMaker.make( new LinkedHashMap<>(),(map) -> { map.put("solarus",this::playSolarus); map.put("lichess",this::playLichess); });
불행히도 키와 값의 유형이 같지 않은 경우 varargs를 사용하는 것은 Object...
를 사용해야 하고 유형 안전성을 완전히 상실해야 하므로 그다지 합리적이지 않습니다. 예를 들어 항상 Map<String, String>
을 만들고 싶다면 물론 toMap(String... args)
가 가능하지만 키와 값을 섞기 쉽고 이상한 인수의 수는 유효하지 않습니다.
다음과 같이 연결 가능한 메서드가 있는 HashMap의 하위 클래스를 만들 수 있습니다.
public class ChainableMap<K, V> extends HashMap<K, V> { public ChainableMap<K, V> set(K k, V v) { put(k, v); return this; } }
new ChainableMap<String, Object>().set("a", 1).set("b", "foo")
처럼 사용하십시오.
또 다른 접근 방식은 공통 빌더 패턴을 사용하는 것입니다.
public class MapBuilder<K, V> { private Map<K, V> mMap = new HashMap<>(); public MapBuilder<K, V> put(K k, V v) { mMap.put(k, v); return this; } public Map<K, V> build() { return mMap; } }
new MapBuilder<String, Object>().put("a", 1).put("b", "foo").build();
그러나 지금 사용한 솔루션은 varargs와 Pair
클래스를 사용합니다.
public class Maps { public static <K, V> Map<K, V> of(Pair<K, V>... pairs) { Map<K, V> = new HashMap<>(); for (Pair<K, V> pair : pairs) { map.put(pair.first, pair.second); } return map; } }
Map<String, Object> map = Maps.of(Pair.create("a", 1), Pair.create("b", "foo");
Pair.create()
의 장황한 표현이 조금 귀찮게 하지만 이것은 꽤 잘 작동합니다. 정적 가져오기가 마음에 들지 않으면 물론 도우미를 만들 수 있습니다.
public <K, V> Pair<K, V> p(K k, V v) { return Pair.create(k, v); }
Map<String, Object> map = Maps.of(p("a", 1), p("b", "foo");
( Pair
Map.Entry
사용하는 것을 상상할 수 있지만 인터페이스이기 때문에 구현 클래스 및/또는 도우미 팩토리 메서드가 필요합니다. 또한 변경할 수 없으며 이 작업에 유용하지 않은 다른 논리가 포함되어 있습니다.)
Java 8에서 Streams를 사용할 수 있습니다(이것은 Set의 예입니다).
@Test public void whenInitializeUnmodifiableSetWithDoubleBrace_containsElements() { Set<String> countries = Stream.of("India", "USSR", "USA") .collect(collectingAndThen(toSet(), Collections::unmodifiableSet)); assertTrue(countries.contains("India")); }
참조: https://www.baeldung.com/java-double-brace-initialization
아래 예와 같이 지도를 초기화하는 메서드를 만들 수 있습니다.
Map<String, Integer> initializeMap() { Map<String, Integer> ret = new HashMap<>(); //populate ret ... return ret; } //call Map<String, Integer> map = initializeMap();
@johnny-willer의 답변에 Collectors.toMap
Map.merge
의존하기 때문에 Java 8에서 null 값이 있는 맵을 얻을 수 없습니다. 이 메서드는 null 값을 예상하지 않으므로 이 버그 보고서에 설명된 대로 NullPointerException
이 발생합니다. https://bugs.openjdk.java.net/browse/JDK-8148463
Java 8에서 빌더 구문을 사용하여 null 값이 있는 맵을 가져오는 다른 방법은 인라인 수집기를 작성하는 것입니다.
Map<String, String> myMap = Stream.of( new SimpleEntry<>("key1", "value1"), new SimpleEntry<>("key2", (String) null), new SimpleEntry<>("key3", "value3")) .collect(HashMap::new, (map, entry) -> map.put(entry.getKey(), entry.getValue()), HashMap::putAll);
또한 이 구현은 키가 여러 번 나타나는 경우 값을 대체합니다. (prev, next) -> next
와 같은 사용자 정의 병합 기능이 없는 기본 Collectors.toMap
은 IllegalStatException
을 발생시킵니다.
다음 코드는 Java 8에서 트릭을 수행할 수 있습니다.
Map<String, Integer> map = Stream.of(new Object[][] { { "data1", 1 }, { "data2", 2 }, }).collect(Collectors.toMap(data -> (String) data[0], data -> (Integer) data[1]));
크레딧 :
Map.of()
는 가장 보편적이고 가장 제한적인 것으로 보입니다. 여기서는 객체가 아닌 입력 값을 자동으로 처리합니다.
List<Map<String, Object> certs = new ArrayList<>(){{ add( Map.of( "TAG", Obj1 // Object "TAGGED_ID", 1L //Long "DEGREE", "PARENT" // String "DATE", LocalDate.now() // LocalDate ));}};
Map.of(..)
의해 생성된 맵은 키도 값도 null
을 허용하지 않습니다.
출처 : http:www.stackoverflow.com/questions/6802483/how-to-directly-initialize-a-hashmap-in-a-literal-way
Bitmap 개체에 이미지를 로드하는 동안 이상한 OutOfMemory 문제 (0) | 2023.04.14 |
---|---|
JavaScript에서 문자열을 자르시겠습니까? (0) | 2023.04.14 |
텍스트 상자의 Enter 키에서 JavaScript로 버튼 클릭 트리거 (0) | 2023.04.14 |
Git 태그의 이름을 어떻게 바꾸나요? (0) | 2023.04.14 |
Python에 디렉토리가 있는지 확인하는 방법 (0) | 2023.04.13 |