繁体   English   中英

什么是在Java中使用的良好的持久性收集框架?

[英]what's a good persistent collections framework for use in java?

永久性收集是指类似于clojure的收集。

例如,我有一个包含元素(a,b,c)的列表。 对于普通列表,如果我添加d,则原始列表将具有(a,b,c,d)作为其元素。 对于持久性列表,当我调用list.add(d)时,我会得到一个新列表,并持有(a,b,c,d)。 但是,该实现尝试尽可能在列表之间共享元素,因此与简单地返回原始列表的副本相比,它的内存效率要高得多。 它还具有不可变的优势(如果我持有对原始列表的引用,那么它将始终返回原始的3个元素)。

所有这些都在其他地方(例如http://en.wikipedia.org/wiki/Persistent_data_structure )得到了更好的解释。

无论如何,我的问题是...提供此功能以在Java中使用的最佳库是什么? 我可以以某种方式使用clojure集合吗(其他方式可以直接使用clojure)?

只需直接在Clojure中使用即可。 虽然显然您可能不想使用它本身的语言,但是您仍然可以直接使用持久性集合,因为它们都是Java类。

import clojure.lang.PersistentHashMap;
import clojure.lang.IPersistentMap;

IPersistentMap map = PersistentHashMap.create("key1", "value1");

assert map.get("key1").equals("value1");
IPersistentMap map2 = map.assoc("key1", "value1");

assert map2 != map;
assert map2.get("key1").equals("value1");

(免责声明:我实际上尚未编译该代码:)

缺点是没有键入集合,即它们没有泛型。

收集呢?

您还可以检查Clojure的持久性集合的实现(例如PersistentHashMap )。

我一直在寻找一个苗条的Java“友好”持久性收集框架,并将该线程中提到的TotallyLazyPCollections用于测试驱动器,因为它们听起来对我来说最有希望。

两者都提供合理的简单接口来操作持久列表:

// TotallyLazy
PersistentList<String> original = PersistentList.constructors.empty(String.class);
PersistentList<String> modified = original.append("Mars").append("Raider").delete("Raider");

// PCollections
PVector<String> original = TreePVector.<String>empty();
PVector<String> modified = original.plus("Mars").plus("Raider").minus("Raider");

PersistentListPVector扩展了java.util.List ,因此这两个库都应很好地集成到现有环境中。

但是事实证明,在处理较大的列表时,TotallyLazy会遇到性能问题 (如@levantpied在上面的注释中已经提到的)。 在我的MacBook Pro(2013年末)上,插入100.000个元素并返回不可变的列表花费了TotallyLazy〜2000ms,而PCollections在〜120ms内完成。

如果有人想更全面地了解我的(简单)测试用例,可以在Bitbucket上找到。

[更新] :最近我查看了Cyclops X ,它是针对函数式编程的高性能且更完整的库。 独眼巨人还包含一个用于持久性收集的模块。

https://github.com/andrewoma/dexx是Scala的持久性集合到Java的移植。 这包括:

  • Set,SortedSet,Map,SortedMap和Vector
  • 适配器以java.util等效项查看持久性集合
  • 轻松施工的助手

功能性Java实现了一个持久列表,惰性列表,集合,映射和树。 可能还有其他内容,但是我只是浏览网站首页上的信息。

我也想知道Java最好的持久性数据结构库是什么。 我的注意力集中在Functional Java上,因为在《 Java开发人员的函数式编程 》一书中提到了它。

您可以使用pcollections (永久集合)库:

http://code.google.com/p/pcollections/

投票最多的答案建议直接使用clojure集合,我认为这是一个很好的主意。 不幸的是,clojure是一种动态类型化的语言,而Java并不是这样的事实,这使得clojure库在Java中使用起来非常不舒服。

因此,由于缺少用于Clojure集合类型的轻巧,易于使用的包装器,我编写了自己的Java包装器库,使用了用于Clojure集合类型的泛型,并着眼于易用性和清晰度到接口。

https://github.com/cornim/ClojureCollections

也许这对某人有用。

PS:目前只实现了PersistentVector,PersistentMap和PersistentList。

Paguro提供了Java 8+中使用的实际Clojure集合的类型安全版本 它包括:列表(向量),HashMap,TreeMap,HashSet和TreeSet。 它们的行为完全符合您在问题中指定的方式,并且已尽力地适合现有的java.util集合接口,以实现最大的类型安全Java兼容性。 它们也比PCollections快一点

用Paguro编码示例如下:

// List with the elements (a,b,c)
ImList<T> list = vec(a,b,c);

// With a persistent list, when I call list.add(d),
// I get back a new list, holding (a,b,c,d)
ImList<T> newList = list.append(d);

list.size(); // still returns 3

newList.size(); // returns 4

你说,

该实现尝试尽可能在列表之间共享元素,因此与简单地返回原始列表的副本相比,它具有更高的内存效率和速度。 它还具有不可变的优势(如果我持有对原始列表的引用,那么它将始终返回原始的3个元素)。

是的,这就是它的行为方式。 丹尼尔·斯皮沃克(Daniel Spiewak)解释了这些收藏的速度和效率要比我更好。

可能想查看clj-ds 我没有用过,但看起来很有希望。 基于项目自述文件,它从Clojure 1.2.0中提取了数据结构。

与Cornelius Mund一样, Pure4J将Clojure集合移植到Java中并添加了对Generics的支持。

但是,Pure4J旨在通过编译时代码检查将纯编程语义引入JVM,因此进一步将不可变性约束引入您的类,以便在存在该集合的情况下不能使该集合的元素发生突变。

这可能不是您想要实现的目标:如果只是在JVM上使用Clojure集合后,我会采用Cornelius的方法,否则,如果您有兴趣在Java中追求纯编程方法,那么您可以Pure4J试试。

披露:我是这个的开发商

totallylazy是一个非常好的FP库,具有以下实现:

  • PersistentList<T> :具体的实现是LinkedList<T>TreeList<T> (用于随机访问)
  • PersistentMap<K, V> :具体的实现是HashTreeMap<K, V>ListMap<K, V>
  • PersistentSortedMap<K, V>
  • PersistentSet<T> :具体的实现是TreeSet<T>

用法示例:

import static com.googlecode.totallylazy.collections.PersistentList.constructors.*;
import com.googlecode.totallylazy.collections.PersistentList;
import com.googlecode.totallylazy.numbers.Numbers;

...

PersistentList<Integer> list = list(1, 2, 3);

// Create a new list with 0 prepended
list = list.cons(0);

// Prints 0::1::2::3
System.out.println(list);

// Do some actions on this list (e.g. remove all even numbers)
list = list.filter(Numbers.odd);
// Prints 1::3
System.out.println(list);

完全懒惰不断被维护。 主要缺点是完全缺少Javadoc。

我很惊讶没有人提到vavr。 我已经使用了很长时间了。

http://www.vavr.io

来自他们网站的描述:

Vavr核心是Java的功能库。 它有助于减少代码量并提高鲁棒性。 进行函数式编程的第一步是开始思考不变的值。 Vavr提供不可变的集合以及必要的功能和控制结构,以对这些值进行操作。 结果是美丽的,并且可以正常工作。

https://github.com/arnohaase/a-foundation是Scala库的另一个端口。

也可以从Maven Central获得:com.ajjpj.a-foundation:a-foundation

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM