HashMap 为未找到的键返回默认值?

发布于 2024-12-06 04:18:54 字数 51 浏览 0 评论 0原文

是否可以让 HashMap 为集合中未找到的所有键返回默认值?

Is it possible to have a HashMap return a default value for all keys that are not found in the set?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

和我恋爱吧 2024-12-13 04:18:55

在 Java/Kotlin 混合项目中,还可以考虑 Kotlin 的 Map.withDefault

请参阅从 Java 访问 Kotlin 扩展函数

In mixed Java/Kotlin projects also consider Kotlin's Map.withDefault.

See Accessing Kotlin extension functions from Java.

追风人 2024-12-13 04:18:54

在 Java 8 中,使用 Map。 getOrDefault。它需要键,如果没有找到匹配的键,则返回值。

In Java 8, use Map.getOrDefault. It takes the key, and the value to return if no matching key is found.

悲念泪 2024-12-13 04:18:54

[更新]

正如其他答案和评论者所指出的,从 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;
  }
}

[Update]

As noted by other answers and commenters, as of Java 8 you can simply call Map#getOrDefault(...).

[Original]

There's no Map implementation that does this exactly but it would be trivial to implement your own by extending 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;
  }
}
北方的巷 2024-12-13 04:18:54

使用 Commons 的 DefaultedMap 如果您不想重新发明轮子,例如,

Map<String, String> map = new DefaultedMap<>("[NO ENTRY FOUND]");
String surname = map.get("Surname"); 
// surname == "[NO ENTRY FOUND]"

如果您不负责创建地图,您也可以传入现有地图。

Use Commons' DefaultedMap if you don't feel like reinventing the wheel, e.g.,

Map<String, String> map = new DefaultedMap<>("[NO ENTRY FOUND]");
String surname = map.get("Surname"); 
// surname == "[NO ENTRY FOUND]"

You can also pass in an existing map if you're not in charge of creating the map in the first place.

无声无音无过去 2024-12-13 04:18:54

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/

免责声明:
这个答案与OP所要求的不完全匹配,但在某些情况下,当键数量有限并且缓存不同值会有利可图时,匹配问题的标题可能会很方便。它不应该在具有大量键和相同默认值的相反情况下使用,因为这会不必要地浪费内存。

Java 8 introduced a nice computeIfAbsent default method to Map interface which stores lazy-computed value and so doesn't break map contract:

Map<Key, Graph> map = new HashMap<>();
map.computeIfAbsent(aKey, key -> createExpensiveGraph(key));

Origin: http://blog.javabien.net/2014/02/20/loadingcache-in-java-8-without-guava/

Disclamer:
This answer doesn't match exactly what OP asked but may be handy in some cases matching question's title when keys number is limited and caching of different values would be profitable. It shouldn't be used in opposite case with plenty of keys and same default value as this would needlessly waste memory.

梦幻的心爱 2024-12-13 04:18:54

难道你不能创建一个静态方法来完成这个任务吗?

private static <K, V> V getOrDefault(Map<K,V> map, K key, V defaultValue) {
    return map.containsKey(key) ? map.get(key) : defaultValue;
}

Can't you just create a static method that does exactly this?

private static <K, V> V getOrDefault(Map<K,V> map, K key, V defaultValue) {
    return map.containsKey(key) ? map.get(key) : defaultValue;
}
唯憾梦倾城 2024-12-13 04:18:54

您可以简单地创建一个继承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;
    }
}

我认为您不应该在实现中重写 get(K key) 方法,因为 Ed Staub 在他的评论中指定的原因,并且因为您将破坏 Map 接口的契约(这可能会导致一些难以理解的问题) - 查找错误)。

You can simply create a new class that inherits HashMap and add getDefault method.
Here is a sample code:

public class DefaultHashMap<K,V> extends HashMap<K,V> {
    public V getDefault(K key, V defaultValue) {
        if (containsKey(key)) {
            return get(key);
        }

        return defaultValue;
    }
}

I think that you should not override get(K key) method in your implementation, because of the reasons specified by Ed Staub in his comment and because you will break the contract of Map interface (this can potentially lead to some hard-to-find bugs).

赠我空喜 2024-12-13 04:18:54

在 Java 8+ 上

Map.getOrDefault(Object key,V defaultValue)

On java 8+

Map.getOrDefault(Object key,V defaultValue)
七分※倦醒 2024-12-13 04:18:54

使用:

myHashMap.getOrDefault(key, defaultValue);

Use:

myHashMap.getOrDefault(key, defaultValue);
风流物 2024-12-13 04:18:54

它默认执行此操作。它返回null

It does this by default. It returns null.

治碍 2024-12-13 04:18:54

我找到了 LazyMap 非常有帮助。

当使用映射中不存在的键调用 get(Object) 方法时,将使用工厂来创建对象。创建的对象将使用请求的密钥添加到地图中。

这允许您执行如下操作:

    Map<String, AtomicInteger> map = LazyMap.lazyMap(new HashMap<>(), ()->new AtomicInteger(0));
    map.get(notExistingKey).incrementAndGet();

get 的调用为给定键创建默认值。您可以指定如何使用 LazyMap.lazyMap(map, factory) 的工厂参数创建默认值。在上面的示例中,映射被初始化为值为 0 的新 AtomicInteger

I found the LazyMap quite helpful.

When the get(Object) method is called with a key that does not exist in the map, the factory is used to create the object. The created object will be added to the map using the requested key.

This allows you to do something like this:

    Map<String, AtomicInteger> map = LazyMap.lazyMap(new HashMap<>(), ()->new AtomicInteger(0));
    map.get(notExistingKey).incrementAndGet();

The call to get creates a default value for the given key. You specify how to create the default value with the factory argument to LazyMap.lazyMap(map, factory). In the example above, the map is initialized to a new AtomicInteger with value 0.

迷爱 2024-12-13 04:18:54
/**
 * 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));
/**
 * 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);
}

Example Usage:

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));
尐偏执 2024-12-13 04:18:54

我需要读取从服务器返回的 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; }
}   

I needed to read the results returned from a server in JSON where I couldn't guarantee the fields would be present. I'm using class org.json.simple.JSONObject which is derived from HashMap. Here are some helper functions I employed:

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; }
}   
深者入戏 2024-12-13 04:18:54
    public final Map<String, List<String>> stringMap = new ConcurrentHashMap<String, List<String>>() {
        @Nullable
        @Override
        public List<String> get(@NonNull Object key) {
            return computeIfAbsent((String) key, s -> new ArrayList<String>());
        }
    };

HashMap会导致死循环,所以使用ConcurrentHashMap代替HashMap,

    public final Map<String, List<String>> stringMap = new ConcurrentHashMap<String, List<String>>() {
        @Nullable
        @Override
        public List<String> get(@NonNull Object key) {
            return computeIfAbsent((String) key, s -> new ArrayList<String>());
        }
    };

HashMap cause dead loop, so use ConcurrentHashMap instead of HashMap,

吖咩 2024-12-13 04:18:54

在使用getOrDefault方法的地图中,如果找不到键,我们可以将默认值放在右侧参数中。

通过对状态进行分组,将列表转换为地图。

Map<String, Long> mapClaimDecisionSummaryCount = reportList.stream().collect(Collectors.groupingBy(Report::getStatus, Collectors.counting()));
Long status_approved = mapClaimDecisionSummaryCount.getOrDefault("APPROVED", 0L);
Long status_declined = mapClaimDecisionSummaryCount.getOrDefault("DECLINED", 0L);
Long status_cancelled = mapClaimDecisionSummaryCount.getOrDefault("CANCELLED", 0L);//If Key not found it takes defaultValue as 0
Long status_inprogress = mapClaimDecisionSummaryCount.getOrDefault("INPROGRESS", 0L);
      
System.out.println("APPROVED: "+ status_approved);
System.out.println("DECLINED: "+ status_declined);
System.out.println("CANCELLED: "+ status_cancelled);
System.out.println("INPROGRESS: "+ status_inprogress);

输出:

APPROVED: 20
DECLINED: 10
CANCELLED: 5
INPROGRESS: 0

如您在上面的输出中看到的,未找到状态INPROGRESS,因此将默认值设置为0

In Map Using getOrDefault method if key is not found we can place the default value in right side parameter.

Converting List to Map by doing grouping Status.

Map<String, Long> mapClaimDecisionSummaryCount = reportList.stream().collect(Collectors.groupingBy(Report::getStatus, Collectors.counting()));
Long status_approved = mapClaimDecisionSummaryCount.getOrDefault("APPROVED", 0L);
Long status_declined = mapClaimDecisionSummaryCount.getOrDefault("DECLINED", 0L);
Long status_cancelled = mapClaimDecisionSummaryCount.getOrDefault("CANCELLED", 0L);//If Key not found it takes defaultValue as 0
Long status_inprogress = mapClaimDecisionSummaryCount.getOrDefault("INPROGRESS", 0L);
      
System.out.println("APPROVED: "+ status_approved);
System.out.println("DECLINED: "+ status_declined);
System.out.println("CANCELLED: "+ status_cancelled);
System.out.println("INPROGRESS: "+ status_inprogress);

OutPut:

APPROVED: 20
DECLINED: 10
CANCELLED: 5
INPROGRESS: 0

As you see in the above output Status INPROGRESS is not found, so it takes Default value as 0

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文