Java 中的持久数据结构

2022-09-02 20:30:53

有没有人知道一个库,或者至少一些关于在Java中创建和使用持久数据结构的研究?我不认为持久性是长期存储,而是不可变性的持久性(参见维基百科条目)。

我目前正在探索为持久结构建模 API 的不同方法。使用构建器似乎是一个有趣的解决方案:

// create persistent instance
Person p = Builder.create(Person.class)
             .withName("Joe")
             .withAddress(Builder.create(Address.class)
                 .withCity("paris")
                 .build())
              .build();

// change persistent instance, i.e. create a new one 
Person p2 = Builder.update(p).withName("Jack");

Person p3 = Builder.update(p)
              .withAddress(Builder.update(p.address())
                .withCity("Berlin")
                .build)
            .build();

但这仍然感觉有些样板。有什么想法吗?


答案 1

构建器会使您的代码过于冗长而无法使用。在实践中,我见过的几乎所有不可变数据结构都通过构造函数传递状态。就其价值而言,这里有一系列很好的文章,描述了C#中的不可变数据结构(应该很容易转换为Java):

C#和Java非常冗长,所以这些文章中的代码非常可怕。我建议学习OCaml,F#或Scala,并熟悉这些语言的不变性。一旦你掌握了这项技术,你将能够更容易地将相同的编码风格应用于Java。


答案 2

我想显而易见的选择是:

o 切换到瞬态数据结构(生成器)进行更新。这很正常。 例如,用于操作。以你为例。StringBuilderString

Person p3 =
    Builder.update(p)
    .withAddress(
        Builder.update(p.address())
       .withCity("Berlin")
       .build()
    )
    .build();

o 始终使用持久结构。尽管似乎有很多复制,但实际上您应该共享几乎所有状态,因此它远没有看起来那么糟糕。

final Person p3 = p
    .withAddress(
        p.address().withCity("Berlin")
    );

o将数据结构分解为大量变量,并与一个巨大且令人困惑的构造函数重新组合。

final Person p3 = Person.of(
    p.name(),
    Address.of(
       p.house(), p.street(), "Berlin", p.country()
    ),
    p.x(),
    p.y(),
    p.z()
 );

o 使用回调接口提供新数据。甚至更多的样板。

final Person p3 = Person.of(new PersonInfo(
    public String  name   () { return p.name(); )
    public Address address() { return Address.of(new AddressInfo() {
       private final Address a = p.address();
       public String house  () { return a.house()  ; }
       public String street () { return a.street() ; }
       public String city   () { return "Berlin"   ; }
       public String country() { return a.country(); }
    })),
    public Xxx     x() { return p.x(); }
    public Yyy     y() { return p.y(); }
    public Zzz     z() { return p.z(); }
 });

o 使用令人讨厌的黑客使字段暂时可用于代码。

final Person p3 = new PersonExploder(p) {{
    a = new AddressExploder(a) {{
        city = "Berlin";
    }}.get();
}}.get();

(有趣的是,我刚刚被克里斯·冈崎(Chris Okasaki)的《纯粹功能数据结构》(Pure Functional Data Structures)的副本放下了。


推荐