什么是在java中使用的好的持久性集合框架?

时间:2011-12-20 12:51:10

标签: java collections clojure functional-programming

通过持久性集合,我的意思是像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)?

13 个答案:

答案 0 :(得分:16)

直接使用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");

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

缺点是集合没有输入,即没有泛型。

答案 1 :(得分:10)

pcollections怎么办?

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

答案 2 :(得分:5)

我一直在寻找一个苗条,Java"友好"持久集合框架并将此线程中提到的MoviePlayerTotallyLazy用于testdrive,因为它们对我来说听起来最有希望。

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

// 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内完成。

我可以在PCollections上找到我的(简单)测试用例,如果有人想要更全面一点的话。

答案 3 :(得分:4)

https://github.com/andrewoma/dexx是Scala对Java的持久集合的一个端口。它包括:

  • Set,SortedSet,Map,SortedMap和Vector
  • 用于将持久性集合视为java.util等效项
  • 的适配器
  • 便于施工的辅助工具

答案 4 :(得分:3)

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

答案 5 :(得分:3)

Functional Java实现持久List,惰性List,Set,Map和Tree。可能还有其他人,但我只是按照网站首页上的信息进行操作。

我也很想知道Java最好的持久数据结构库是什么。我的注意力集中在功能Java上,因为书中提到了Functional Programming for Java Developers

答案 6 :(得分:3)

您可以使用pcollections(持久收藏集)库:

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

答案 7 :(得分:3)

Paguro provides type-safe versions of the actual Clojure collections用于Java 8+。它包括:List(Vector),HashMap,TreeMap,HashSet和TreeSet。它们的行为与您在问题中指定的方式完全相同,并且painstakingly fit into the existing java.util collections interfaces具有最大的类型安全Java兼容性。它们也是a little faster than 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 explains the speed and efficiency of these collections比我更好。

答案 8 :(得分:2)

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

然而,Pure4J旨在通过编译时代码检查将纯编程语义引入JVM,因此它进一步向类引入不可变性约束,以便在集合存在时不能突变集合的元素。 / p>

这可能是你想要实现的,也可能不是你想要实现的:如果你刚刚在JVM上使用Clojure集合,我会采用Cornelius的方法,否则,如果你有兴趣在Java中寻求纯编程方法那么你可以尝试一下Pure4J。

披露:我是

的开发者

答案 9 :(得分:1)

最高投票回答建议直接使用clojure集合,我认为这是一个非常好的主意。不幸的是,clojure是一种动态类型语言而Java不会使clojure库在Java中使用时非常不舒服。

由于这个以及缺乏用于clojure集合类型的轻量级,易于使用的包装器,我使用泛型为clojure集合类型编写了我自己的Java包装器库,重点是易用性和清晰度谈到接口。

https://github.com/cornim/ClojureCollections

也许这会对某人有用。

P.S。:目前只实施了PersistentVector,PersistentMap和PersistentList。

答案 10 :(得分:1)

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。

答案 11 :(得分:1)

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

http://www.vavr.io

他们网站上的描述

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

答案 12 :(得分:0)

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

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