다음과 같이 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.ofJava 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);