다음과 같이 Java HashMap을 초기화하는 방법이 있습니까? :
Map<String,String> test =
new HashMap<String, String>{"test":"test","test":"test"};
올바른 구문은 무엇입니까? 나는 이것에 관해 아무것도 찾지 못했다. 이것이 가능한가? 지도를 만들 때 절대 변경되지 않고 미리 알려진 일부 "최종 / 정적"값을지도에 넣는 가장 짧고 빠른 방법을 찾고 있습니다.
다음과 같이 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;
}
Collections.singletonMap()
:
entry
문서화되어 있습니까?
이것은 한 가지 방법입니다.
HashMap<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);
타사 라이브러리를 허용하면 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에는 맵 리터럴이 없습니다 (아직 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);
}
};
HashMap
를이 하위 클래스로 하드 코딩합니다 . 실제로 제공 한 경우에만 작동합니다. (새로운 (빈) HashMap에서는 형식 인수가 관련이 없습니다.)
대안은 일반 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");
Map.of…
Java 9 이상에서 메소드를 사용하십시오 .
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
을 인스턴스화하십시오 .
맵 (항목 모음)은 변경할 수 없으므로 인스턴스화 후 항목을 추가하거나 제거 할 수 없습니다. 또한 각 항목의 키와 값은 변경할 수 없으며 변경할 수 없습니다. NULL이 허용되지 않거나 중복 키가 허용되지 않으며 맵핑의 반복 순서는 임의적 인 다른 규칙에 대해서는 Javadoc 을 참조하십시오 .
우리가 요일에 근무할 것으로 예상되는 사람에게 요일 맵에 대한 일부 샘플 데이터를 사용하여 이러한 방법을 살펴 보겠습니다.
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
)
;
weekendWorker.toString () : {SUNDAY = 사람 {name = 'Bob'}, SATURDAY = 사람 {name = 'Alice'}}
Map.ofEntries( … )
Map.ofEntries( Map.Entry , … )
Map.Entry
인터페이스를 구현하는 많은 수의 객체를 가져옵니다 . 자바는 그 인터페이스, 하나 개의 가변, 다른 불변을 구현하는 두 개의 클래스를 번들 : 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 = 사람 {name = 'Bob'}, 화요일 = 사람 {name = 'Bob'}, THURSDAY = 사람 {name = 'Carol'}, FRIDAY = 사람 {name = 'Carol'} , MONDAY = 사람 {name = 'Alice'}}
Map.copyOf
자바 10은 그 방법을 추가했다 Map.copyOf
. 기존지도를 전달하고 해당지도의 불변 사본을 다시 가져옵니다.
공지 사항지도의 반복자 순서가 생산 것을 통해이 Map.of
되어 있지 보장. 항목은 임의의 순서로되어 있습니다. 설명서는 주문이 변경 될 수 있음을 경고하므로 표시된 순서에 따라 코드를 작성하지 마십시오.
이 모든 것을 참고 Map.of…
방법이를 반환 Map
으로 지정되지 않은 클래스 . 기본 콘크리트 클래스는 Java 버전마다 다를 수 있습니다. 이 익명 성을 통해 Java는 특정 데이터에 가장 적합한 것이 무엇이든 다양한 구현 중에서 선택할 수 있습니다. 예를 들어, 키가 enum 에서 온 경우 Java EnumMap
는 표지 아래를 사용할 수 있습니다 .
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)));
}};
}
참고이 클래스를 사용할 때마다 익명 클래스가 만들어 지므로 모든 것에 사용하지 않는 것이 좋습니다.
자바 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));
이는 익명 클래스를 만들지 않는 이점이 있습니다.
수입품은 다음과 같습니다.
import static java.util.stream.Collectors.toMap;
import java.util.AbstractMap.SimpleEntry;
물론 다른 답변에서 언급했듯이 Java 9부터는 동일한 작업을 수행하는 간단한 방법이 있습니다.
불행히도 키와 값의 유형이 동일하지 않은 경우 varargs를 사용하는 것은 Object...
유형 안전을 완전히 사용 하고 잃어 버릴 정도로 합리적이지 않습니다 . 예를 들어 항상 a을 만들고 싶다면 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에서 스트림을 사용할 수 있습니다 (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
키-값 쌍을 하나만 배치해야하는 경우 Collections.singletonMap (key, value);