HashMap
세트에서 찾을 수없는 모든 키에 대해 기본값을 반환 할 수 있습니까?
HashMap
세트에서 찾을 수없는 모든 키에 대해 기본값을 반환 할 수 있습니까?
답변:
[최신 정보]
다른 답변과 의견 작성자가 언급했듯이 Java 8부터 간단히 전화 할 수 있습니다 Map#getOrDefault(...)
.
[실물]
이 작업을 정확히 수행하는 Map 구현은 없지만 HashMap을 확장하여 직접 구현하는 것은 쉽지 않습니다.
public class DefaultHashMap<K,V> extends HashMap<K,V> {
protected V defaultValue;
public DefaultHashMap(V defaultValue) {
this.defaultValue = defaultValue;
}
@Override
public V get(Object k) {
return containsKey(k) ? super.get(k) : defaultValue;
}
}
(v == null)
에 (v == null && !this.containsKey(k))
경우에 그들은 의도적 추가 된 null
값입니다. 알다시피, 이것은 모퉁이의 경우에 해당하지만 저자는 문제가 발생할 수 있습니다.
!this.containsValue(null)
. 이것은 미묘하게 다릅니다 !this.containsKey(k)
. containsValue
어떤 경우 솔루션은 실패하게됩니다 다른 키가 명시 적으로 값을 할당하고있다 null
. 예를 들어 map = new HashMap(); map.put(k1, null); V v = map.get(k2);
,이 경우 v
에도 여전히 null
맞습니까?
Java 8에서는 Map.getOrDefault를 사용 하십시오 . 일치하는 키가 없으면 키를 반환하고 값을 반환합니다.
getOrDefault
매우 훌륭하지만 맵에 액세스 할 때마다 기본 정의가 필요합니다. 기본값을 한 번 정의하면 정적 값 맵을 작성할 때 가독성이 향상됩니다.
private static String get(Map map, String s) { return map.getOrDefault(s, "Error"); }
바퀴를 재발견하고 싶지 않다면 Commons의 DefaultedMap을 사용하십시오 .
Map<String, String> map = new DefaultedMap<>("[NO ENTRY FOUND]");
String surname = map.get("Surname");
// surname == "[NO ENTRY FOUND]"
처음에지도 작성을 담당하지 않는 경우 기존지도를 전달할 수도 있습니다.
Java 8 은 게으른 계산 값을 저장하고 맵 계약을 위반하지 않는 인터페이스에 멋진 computeIfAbsent 기본 메소드를 도입했습니다 Map
.
Map<Key, Graph> map = new HashMap<>();
map.computeIfAbsent(aKey, key -> createExpensiveGraph(key));
출처 : http://blog.javabien.net/2014/02/20/loadingcache-in-java-8-without-guava/
Disclamer : 이 답변은 OP가 요청한 것과 정확히 일치하지 않지만 키 번호가 제한되어 있고 다른 값의 캐싱이 수익성이있는 경우 질문 제목과 일치하는 경우에 유용 할 수 있습니다. 메모리가 불필요하게 낭비되므로 키가 많고 기본값이 같은 반대의 경우에는 사용하면 안됩니다.
정확히 이것을 수행하는 정적 메소드를 작성할 수 없습니까?
private static <K, V> V getOrDefault(Map<K,V> map, K key, V defaultValue) {
return map.containsKey(key) ? map.get(key) : defaultValue;
}
HashMap을 상속하는 새 클래스를 작성하고 getDefault 메소드를 추가하기 만하면됩니다. 다음은 샘플 코드입니다.
public class DefaultHashMap<K,V> extends HashMap<K,V> {
public V getDefault(K key, V defaultValue) {
if (containsKey(key)) {
return get(key);
}
return defaultValue;
}
}
Ed Staub가 언급 한 이유와 Map 인터페이스 계약 을 위반하기 때문에 구현에서 get (K key) 메소드를 재정의해서는 안된다고 생각합니다 (이는 잠재적으로 찾기 어려운 결과를 초래할 수 있음) 버그).
get
메서드를 재정의하지 않는 것이 중요합니다 . 반면에-귀하의 솔루션은 인터페이스를 통한 클래스 사용을 허용하지 않습니다.
기본적으로이 작업을 수행합니다. 를 반환합니다 null
.
HashMap
때이 기능 을 위해 서브 클래스를 작성하는 것이 조금 어리석은 것처럼 보입니다 null
.
NullObject
패턴을 사용하고 있거나 코드 전체에 null 검사를 분산시키지 않으려는 경우 좋지 않습니다. 완전히 이해하고 싶습니다.
맵에 존재하지 않는 키로 get (Object) 메소드를 호출하면 팩토리가 오브젝트를 작성하는 데 사용됩니다. 생성 된 객체는 요청 된 키를 사용하여 맵에 추가됩니다.
이를 통해 다음과 같은 작업을 수행 할 수 있습니다.
Map<String, AtomicInteger> map = LazyMap.lazyMap(new HashMap<>(), ()->new AtomicInteger(0));
map.get(notExistingKey).incrementAndGet();
get
주어진 키에 대한 기본값 을 생성하기위한 호출 factory 인수를 사용하여 기본값을 작성하는 방법을 지정합니다 LazyMap.lazyMap(map, factory)
. 위의 예에서 맵은 AtomicInteger
값이 0 인 새 것으로 초기화됩니다 .
/**
* Extension of TreeMap to provide default value getter/creator.
*
* NOTE: This class performs no null key or value checking.
*
* @author N David Brown
*
* @param <K> Key type
* @param <V> Value type
*/
public abstract class Hash<K, V> extends TreeMap<K, V> {
private static final long serialVersionUID = 1905150272531272505L;
/**
* Same as {@link #get(Object)} but first stores result of
* {@link #create(Object)} under given key if key doesn't exist.
*
* @param k
* @return
*/
public V getOrCreate(final K k) {
V v = get(k);
if (v == null) {
v = create(k);
put(k, v);
}
return v;
}
/**
* Same as {@link #get(Object)} but returns specified default value
* if key doesn't exist. Note that default value isn't automatically
* stored under the given key.
*
* @param k
* @param _default
* @return
*/
public V getDefault(final K k, final V _default) {
V v = get(k);
return v == null ? _default : v;
}
/**
* Creates a default value for the specified key.
*
* @param k
* @return
*/
abstract protected V create(final K k);
}
사용법 예 :
protected class HashList extends Hash<String, ArrayList<String>> {
private static final long serialVersionUID = 6658900478219817746L;
@Override
public ArrayList<Short> create(Short key) {
return new ArrayList<Short>();
}
}
final HashList haystack = new HashList();
final String needle = "hide and";
haystack.getOrCreate(needle).add("seek")
System.out.println(haystack.get(needle).get(0));
필드가 존재할 것이라고 보장 할 수없는 JSON 서버에서 반환 된 결과를 읽어야했습니다. HashMap에서 파생 된 org.json.simple.JSONObject 클래스를 사용하고 있습니다. 내가 사용한 도우미 기능은 다음과 같습니다.
public static String getString( final JSONObject response,
final String key )
{ return getString( response, key, "" ); }
public static String getString( final JSONObject response,
final String key, final String defVal )
{ return response.containsKey( key ) ? (String)response.get( key ) : defVal; }
public static long getLong( final JSONObject response,
final String key )
{ return getLong( response, key, 0 ); }
public static long getLong( final JSONObject response,
final String key, final long defVal )
{ return response.containsKey( key ) ? (long)response.get( key ) : defVal; }
public static float getFloat( final JSONObject response,
final String key )
{ return getFloat( response, key, 0.0f ); }
public static float getFloat( final JSONObject response,
final String key, final float defVal )
{ return response.containsKey( key ) ? (float)response.get( key ) : defVal; }
public static List<JSONObject> getList( final JSONObject response,
final String key )
{ return getList( response, key, new ArrayList<JSONObject>() ); }
public static List<JSONObject> getList( final JSONObject response,
final String key, final List<JSONObject> defVal ) {
try { return response.containsKey( key ) ? (List<JSONObject>) response.get( key ) : defVal; }
catch( ClassCastException e ) { return defVal; }
}
혼합 Java / Kotlin 프로젝트에서는 Kotlin의 Map.withDefault 도 고려 하십시오 .