Java 如何将可变对象编排为跨对象的不可变对象

Java 如何将可变对象编排为跨对象的不可变对象,java,immutability,immutable-collections,Java,Immutability,Immutable Collections,我有一个类似这样的java类 class Runner { public Object run(Map<String, Object> input); public String name(); } public class Test { public static void main(String args[]) { Map<String, Object> map = Maps.newHashMap(); List<Runner

我有一个类似这样的java类

class Runner {
  public Object run(Map<String, Object> input);
  public String name();
}

public class Test {

  public static void main(String args[]) {  
    Map<String, Object> map = Maps.newHashMap();
    List<Runner> runners;
    forEach(Runner runner: runners) {
      Object obj = runner.run(map);
      map.put(runner.name(), obj);
    }
  }

}
类运行程序{
公共对象运行(映射输入);
公共字符串名称();
}
公开课考试{
公共静态void main(字符串args[]){
Map Map=Maps.newHashMap();
列出跑步者名单;
forEach(跑步者:跑步者){
objectobj=runner.run(map);
map.put(runner.name(),obj);
}
}
}

在上面的代码中,我调用Runner类的run方法,并将其生成的输出添加到Map对象中。对于流道对象列表,重复此操作。如何使作为输入传递给run方法的map对象不可变?我考虑从映射中创建一个不可变的映射,并将其作为输入参数传递。但我担心的是,根据运行程序对象执行的数量,我可能创建的不可变映射的数量可能会导致OOM错误。有没有任何模式或解决方案可供选择?任何建议都将不胜感激。

如果您只是通过
运行
方法中的键获取地图值,那么您可以使用
函数
界面包装您的
地图

class Runner {
  public Object run(Function<String, Object> getter) {}
  public String name() {}
}

public static void main(String args[]) {  
  Map<String, Object> map = new HashMap<>();
  List<Runner> runners;
  for(Runner runner: runners) {
    Object obj = runner.run(map::get);
    map.put(runner.name(), obj);
  }
}
类运行程序{
公共对象运行(函数getter){}
公共字符串名称(){}
}
公共静态void main(字符串args[]){
Map Map=newhashmap();
列出跑步者名单;
用于(跑步者:跑步者){
objectobj=runner.run(map::get);
map.put(runner.name(),obj);
}
}

您可以通过可修改的地图来支持不可修改的地图

它们具有相同的底层数据,但对setter API的访问在不可修改的包装中受到限制

更新可修改的映射时,即使您正在从不可修改的映射读取,以下代码段仍将打印
1
。您可能会注意到,它不会创建地图数据的两个副本,它们只是共享相同的值

Map<String, String> modifiableMap = new HashMap<>();
Map<String, String> unmodifiableMap = Collections.unmodifiableMap(modifiableMap);
modifiableMap.put("a", "1");
System.out.println(unmodifiableMap.get("a"));

不可变映射的可能副本可以在运行程序返回时立即进行垃圾收集,所以这不应该是一个问题。您可以在循环之前创建一次,也许javac或jit足够聪明,可以做到这一点。我怀疑lambda表达式是否会被缓存,但至少这样可以避免创建具有重复项的二级映射,从而使其不可修改。
public static void main(String args[]) {
    Map<String, Object> modifiableMap = Maps.newHashMap();
    Map<String, Object> unmodifiableMap = Collections.unmodifiableMap(modifiableMap);
    List<Runner> runners;
    forEach(Runner runner: runners) {
        Object obj = runner.run(unmodifiableMap);
        modifiableMap.put(runner.name(), obj);
    }
}