Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 具有相同密钥的多个条目不可变映射错误_Java_Multithreading_Guava_Builder_Builder Pattern - Fatal编程技术网

Java 具有相同密钥的多个条目不可变映射错误

Java 具有相同密钥的多个条目不可变映射错误,java,multithreading,guava,builder,builder-pattern,Java,Multithreading,Guava,Builder,Builder Pattern,我在多线程应用程序中使用了一个bellowbuilder类,所以我使它成为线程安全的。为了简单起见,我在这里只展示了几个字段来演示这个问题 public final class ClientKey { private final long userId; private final int clientId; private final String processName; private final Map<String, String> parameterMap

我在多线程应用程序中使用了一个bellowbuilder类,所以我使它成为线程安全的。为了简单起见,我在这里只展示了几个字段来演示这个问题

public final class ClientKey {
  private final long userId;
  private final int clientId;
  private final String processName;
  private final Map<String, String> parameterMap;

  private ClientKey(Builder builder) {
    this.userId = builder.userId;
    this.clientId = builder.clientId;
    this.processName = builder.processName;
    // initializing the required fields
    // and below line throws exception once I try to clone the `ClientKey` object
    builder.parameterMap.put("is_clientid", (clientId == 0) ? "false" : "true");
    this.parameterMap = builder.parameterMap.build();
  }

  public static class Builder {
    private final long userId;
    private final int clientId;
    private String processName;
    private ImmutableMap.Builder<String, String> parameterMap = ImmutableMap.builder();

    // this is for cloning
    public Builder(ClientKey key) {
      this.userId = key.userId;
      this.clientId = key.clientId;
      this.processName = key.processName;
      this.parameterMap =
          ImmutableMap.<String, String>builder().putAll(key.parameterMap);
    }

    public Builder(long userId, int clientId) {
      this.userId = userId;
      this.clientId = clientId;
    }

    public Builder parameterMap(Map<String, String> parameterMap) {
      this.parameterMap.putAll(parameterMap);
      return this;
    }

    public Builder processName(String processName) {
      this.processName = processName;
      return this;
    }

    public ClientKey build() {
      return new ClientKey(this);
    }
  }

  // getters
}
现在,当我尝试克隆如下所示的
keys
对象时,它抛出异常

ClientKey clonedKey = new ClientKey.Builder(keys).processName("hello").build();
它抛出异常,错误消息如下:
java.lang.IllegalArgumentException:具有相同键的多个条目:is_clientid=true和is_clientid=true

builder.parameterMap.put("is_clientid", (clientId == 0) ? "false" : "true");
// from below line exception is coming
this.parameterMap = builder.parameterMap.build();

我如何解决这个问题?我想使我的映射不可变,但我还想用必填字段初始化,并且我只能在
ClientKey
类的构造函数中进行初始化。克隆
ClientKey
对象时,它会引发异常。

您会遇到异常,因为您试图在单个
ClientKey.Builder
类所使用的
ImmutableMap.Builder
中为key
设置值

builder.parameterMap.put("is_clientid", (clientId == 0) ? "false" : "true");
如图所示:

将键与生成的映射中的值相关联。不允许使用重复的密钥,这将导致
build()
失败

不要重复使用
ImmutableMap.Builder
的同一实例

您可以像这样克隆对象:

public ClientKey(ClientKey copyee) {
    // Copy fields here
    this.parameterMap = ImmutableMap.copyOf(copyee.parameterMap);
}
如果要使用某种生成器对象,可以执行以下操作:

public Builder(ClientKey copyee) {
    this.oldParameterMap = copyee.parameterMap;
}

public ClientKey build() {
    // Create new map here and pass it to new ClientKey somehow
    ImmutableMap.copyOf(oldParameterMap);
    return newKey;
}

您遇到异常,因为您正试图为单个
ClientKey.Builder使用的
ImmutableMap.Builder
类中的密钥
is\u clientid
设置一个值:

builder.parameterMap.put("is_clientid", (clientId == 0) ? "false" : "true");
如图所示:

将键与生成的映射中的值相关联。不允许使用重复的密钥,这将导致
build()
失败

不要重复使用
ImmutableMap.Builder
的同一实例

您可以像这样克隆对象:

public ClientKey(ClientKey copyee) {
    // Copy fields here
    this.parameterMap = ImmutableMap.copyOf(copyee.parameterMap);
}
如果要使用某种生成器对象,可以执行以下操作:

public Builder(ClientKey copyee) {
    this.oldParameterMap = copyee.parameterMap;
}

public ClientKey build() {
    // Create new map here and pass it to new ClientKey somehow
    ImmutableMap.copyOf(oldParameterMap);
    return newKey;
}

构造
ClientKey
时,将
的“is\u clientid”
键放入映射中。因此,如果调用
ClientKey.Builder(ClientKey)
构造函数,
putAll
调用将把它复制到新的
ImmutableMap.Builder
实例中。然后,当您构建克隆的
ClientKey
时,
ClientKey
构造函数将再次尝试向映射添加相同的键,这会导致异常

ClientKey clonedKey = new ClientKey.Builder(keys).processName("hello").build();
ImmutableMap.Builder
本可以用不同的方式编写,但事实并非如此。如果你想使用它,你就必须接受它

一种解决方案是不将带有
“is_clientid”
键的条目复制到
生成器的构造函数中的新
ImmutableMap.Builder
。而不是
this.parameterMap=ImmutableMap.builder().putAll(key.parameterMap)你写:

this.parameterMap = new ImmutableMap.Builder<>();
for (Map.Entry<String,String> entry : key.parameterMap.entrySet()) {
    if (!"is_clientid".equals(entry.getKey()) {
        this.parameterMap.put(entry.getKey(), entry.getValue());
    }
}
this.parameterMap = Collections.unmodifiableMap(builder.parameterMap);
你也可以写:

this.parameterMap = ImmutableMap.copyOf(builder.parameterMap);
但这会生成地图的完整副本,对于非常大的地图,这可能需要一些时间


最后一句话:如果你只想复制一个
ClientKey
,你不需要一个生成器;惯用Java将使用复制构造函数或
clone()
方法(尽管有些人不鼓励使用后者)。

当您构建
ClientKey
时,
将“is\u clientid”
键放在映射中。因此,如果调用
ClientKey.Builder(ClientKey)
构造函数,
putAll
调用将把它复制到新的
ImmutableMap.Builder
实例中。然后,当您构建克隆的
ClientKey
时,
ClientKey
构造函数将再次尝试向映射添加相同的键,这会导致异常

ClientKey clonedKey = new ClientKey.Builder(keys).processName("hello").build();
ImmutableMap.Builder
本可以用不同的方式编写,但事实并非如此。如果你想使用它,你就必须接受它

一种解决方案是不将带有
“is_clientid”
键的条目复制到
生成器的构造函数中的新
ImmutableMap.Builder
。而不是
this.parameterMap=ImmutableMap.builder().putAll(key.parameterMap)你写:

this.parameterMap = new ImmutableMap.Builder<>();
for (Map.Entry<String,String> entry : key.parameterMap.entrySet()) {
    if (!"is_clientid".equals(entry.getKey()) {
        this.parameterMap.put(entry.getKey(), entry.getValue());
    }
}
this.parameterMap = Collections.unmodifiableMap(builder.parameterMap);
你也可以写:

this.parameterMap = ImmutableMap.copyOf(builder.parameterMap);
但这会生成地图的完整副本,对于非常大的地图,这可能需要一些时间


最后一句话:如果你只想复制一个
ClientKey
,你不需要一个生成器;惯用Java会使用复制构造函数或
clone()
方法(尽管有些人不鼓励使用后者)。

您能澄清错误消息的抛出位置吗?从上面的代码来看,
ClientKey clonedKey=new ClientKey.Builder(keys.processName(“hello”).build()似乎并不清楚
将引发异常,因为您甚至没有密钥
is\u clientid
。代码中的下一行发生在哪里?您确定这确实是生成器模式的实例吗?--我从未见过有人将“生成器”传递给私有构造函数只是为了设置新对象的字段。@jamesw1234在这一行
this.parameterMap=builder.parameterMap.build()抛出异常
但仅当我尝试将
keys
对象克隆到一个新的
clonedKey
对象时,因为在克隆时,我的
ClientKey
构造函数将被再次调用,然后它将尝试再次将相同的
is\u clientid
插入映射,这就是它引发异常的原因。在哪里实例化了
builder
呢?您能否澄清错误消息是在哪里引发的?从上面的代码来看,
ClientKey clonedKey=new ClientKey.Builder(keys.processName(“hello”).build()似乎并不清楚
将引发异常,因为您甚至没有密钥
is\u clientid
。代码中的下一行发生在哪里?您确定这确实是生成器模式的实例吗?--我从未见过有人将“生成器”传递给私有构造函数只是为了设置新对象的字段。@jamesw1234在这一行
this.parameterMap=builder.parameter抛出异常