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 도 고려 하십시오 .