如何在Java中使用有限的堆栈处理不可变列表?
我正在使用一个API,该API为我提供了大型不可变列表,如下所示:如何在Java中使用有限的堆栈处理不可变列表?,java,recursion,immutability,Java,Recursion,Immutability,我正在使用一个API,该API为我提供了大型不可变列表,如下所示: class List<T> { final T e; final List<T> next; public List(T e, List<T> next) { this.e = e; this.next = next; } } 但是一旦我有了超过9000个元素,我就会得到StackOverflowError(将I更改为从1000
class List<T> {
final T e;
final List<T> next;
public List(T e, List<T> next) {
this.e = e;
this.next = next;
}
}
但是一旦我有了超过9000个元素,我就会得到StackOverflowError
(将I
更改为从10000开始,而不是A
中的9000开始):
因此,我更改了B
以使用不同的策略来增加列表元素:
class B {
static List<Integer> incrementList(List<Integer> l) {
return ListIncrementer.call(l);
}
}
class ListIncrementer extends Thread {
List<Integer> l;
List<Integer> result;
ListIncrementer(List<Integer> l) {
this.l = l;
}
public void run() {
if (l == null) {
result = null;
return;
}
result = new List<Integer>(l.e+1,call(l.next));
}
static List<Integer> call(List<Integer> l) {
ListIncrementer li = new ListIncrementer(l);
li.start();
try { li.join(); } catch (Exception _) {}
return li.result;
}
}
正如预期的那样,它起作用了
但是,我仍然只能使用此方法执行大约30000个元素,这是当我在A
中将I
设置为50000时发生的情况:
Exception in thread "Thread-32290" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:657)
at ListIncrementer.call(A.java:25)
at ListIncrementer.run(A.java:21)
0 -> 1
1 -> 2
2 -> 3
Exception in thread "main" java.lang.NoSuchMethodError: main
(请注意,列表的开头已成功创建,但在结尾的某个地方,它中断并以null
结束)
这意味着它仍然不如用于构建列表的普通迭代那么好。这让我想到也许操纵大型不可变列表是不可能的。我经常听到Java开发人员说,最佳实践是使用不可变结构,然而,除了我提到的API之外,我找不到任何实现这一点的库,而且我自己也无法让它工作。其他开发人员是如何取得这样的成就的?以迭代方式而不是递归方式进行。(而且,“不可变列表”不必按照链接列表的方式设计。)以迭代方式而不是递归方式进行设计。(另外,“不可变列表”不必像链表那样设计。)不要使用递归。使用迭代循环:
class B {
static List<Integer> incrementList(List<Integer> l) {
ArrayList<Integer> elements = new ArrayList<Integer>();
while (l != null) {
elements.add(l.e + 1);
l = l.next;
}
List<Integer> result = null;
for (int i = elements.length - 1; i >= 0; i--) {
result = new List<Integer>(elements.get(i), result);
}
return result;
}
}
B类{
静态列表增量列表(列表l){
ArrayList元素=新的ArrayList();
while(l!=null){
增加(l.e+1);
l=l.next;
}
列表结果=空;
对于(int i=elements.length-1;i>=0;i--){
结果=新列表(elements.get(i),result);
}
返回结果;
}
}
这就是说,这样的列表实现,特别是像标准的
java.util.List
这样的命名列表,并不是一个好主意。不要使用递归。使用迭代循环:
class B {
static List<Integer> incrementList(List<Integer> l) {
ArrayList<Integer> elements = new ArrayList<Integer>();
while (l != null) {
elements.add(l.e + 1);
l = l.next;
}
List<Integer> result = null;
for (int i = elements.length - 1; i >= 0; i--) {
result = new List<Integer>(elements.get(i), result);
}
return result;
}
}
B类{
静态列表增量列表(列表l){
ArrayList元素=新的ArrayList();
while(l!=null){
增加(l.e+1);
l=l.next;
}
列表结果=空;
对于(int i=elements.length-1;i>=0;i--){
结果=新列表(elements.get(i),result);
}
返回结果;
}
}
这就是说,这样的列表实现,特别是像标准的
java.util.List
,命名为List,并不是一个好主意。将递归函数转换为循环(伪代码):
通常,不需要反转结果列表,因为顺序无关紧要,或者您还有另一个转换要做。将递归函数转换为循环(伪代码):
通常,不需要反转结果列表,因为顺序无关紧要,或者您还有其他转换要做。使用它非常不愉快(如OP的问题所示),它在公共属性中公开其内部,并使用一个已经在3个Java类中的2个类中使用的名称来引用另一个类,那么,如何创建一个易于使用的不可变列表呢?让我们在这里忽略“问题”这个名称,因为重命名它很简单。如果这些字段是不可变的,你为什么关心将它们私有化呢?我会使用Guava的ImutableList,而不是重新发明轮子。将字段公开,即使不会使类可变,也不可能更改其实现。这就是封装的全部要点:能够在不更改公共接口的情况下更改内部私有实现。我知道Guava,但这不是我想要的,它似乎只是提供了一个封装在类中的数组。我想从技术上来说,你可以把数组称为列表。。。我想要的是一个不可变的列表,即带有O(1)prepend操作,我的实现实现了这一点。使用它非常不愉快(正如OP的问题所示),它在公共属性中公开了它的内部,并且它使用了一个已经在三分之二的Java类中使用的名称来引用另一个,那么,如何创建一个易于使用的不可变列表呢?让我们在这里忽略“问题”这个名称,因为重命名它很简单。如果这些字段是不可变的,你为什么关心将它们私有化呢?我会使用Guava的ImutableList,而不是重新发明轮子。将字段公开,即使不会使类可变,也不可能更改其实现。这就是封装的全部要点:能够在不更改公共接口的情况下更改内部私有实现。我知道Guava,但这不是我想要的,它似乎只是提供了一个封装在类中的数组。我想从技术上来说,你可以把数组称为列表。。。我想要的是一个不可变的列表,即带有O(1)前置操作的列表,这是我的实现所实现的。
class B {
static List<Integer> incrementList(List<Integer> l) {
return ListIncrementer.call(l);
}
}
class ListIncrementer extends Thread {
List<Integer> l;
List<Integer> result;
ListIncrementer(List<Integer> l) {
this.l = l;
}
public void run() {
if (l == null) {
result = null;
return;
}
result = new List<Integer>(l.e+1,call(l.next));
}
static List<Integer> call(List<Integer> l) {
ListIncrementer li = new ListIncrementer(l);
li.start();
try { li.join(); } catch (Exception _) {}
return li.result;
}
}
javac A.java && java A
0 -> 1
1 -> 2
2 -> 3
Exception in thread "main" java.lang.NoSuchMethodError: main
Exception in thread "Thread-32290" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:657)
at ListIncrementer.call(A.java:25)
at ListIncrementer.run(A.java:21)
0 -> 1
1 -> 2
2 -> 3
Exception in thread "main" java.lang.NoSuchMethodError: main
class B {
static List<Integer> incrementList(List<Integer> l) {
ArrayList<Integer> elements = new ArrayList<Integer>();
while (l != null) {
elements.add(l.e + 1);
l = l.next;
}
List<Integer> result = null;
for (int i = elements.length - 1; i >= 0; i--) {
result = new List<Integer>(elements.get(i), result);
}
return result;
}
}
List increment(List in) {
List out = new empty list;
while (in is not empty) {
out = new out(in.e+1, out);
in = in.next;
}
return need it in same order as before? reverse(out) : out;
}