在Java中,尾部递归函数仍然会破坏堆栈

在Java中,尾部递归函数仍然会破坏堆栈,java,biginteger,tail-recursion,factorial,Java,Biginteger,Tail Recursion,Factorial,我正在尝试实现一个尾部递归阶乘计算器,但仍然得到堆栈溢出。有谁能帮我找出原因吗 我已经读到Java8支持尾部调用优化,但我认为我一定没有正确地实现它 我已经读到可以使用lambda表达式。我不确定我是否完全理解这个概念,但我仍在阅读 我只是在寻找任何关于如何使用真正的尾部调用优化、lambda表达式或我能做的任何事情的建议 代码: package factorielRecursiveTerminale; 导入java.math.biginger; 导入java.util.Scanner; 公

我正在尝试实现一个尾部递归阶乘计算器,但仍然得到堆栈溢出。有谁能帮我找出原因吗

  • 我已经读到Java8支持尾部调用优化,但我认为我一定没有正确地实现它
  • 我已经读到可以使用lambda表达式。我不确定我是否完全理解这个概念,但我仍在阅读
  • 我只是在寻找任何关于如何使用真正的尾部调用优化、lambda表达式或我能做的任何事情的建议
代码:

package factorielRecursiveTerminale;
导入java.math.biginger;
导入java.util.Scanner;
公共类factorielRecursiveTerminale{
公共静态biginger factoriel(biginger n,biginger m){
if(n.compareTo(BigInteger.ZERO)<1)返回m;
返回factoriel(n.subtract(biginger.ONE),n.multiply(m));
}                                                               
公共静态BigInteger事实(int n){//convertir l'entre en BigInteger et lancer la递归
if(n<0){
返回BigInteger.valueOf(-1);
}
BigInteger b=BigInteger.valueOf(n);
返回factoriel(b,biginger.ONE);
}
public static void runBigFact(){//erreurs的手势+boucle d'entre de valeurs。
字符串valeurRecu=“”;
瓦勒尔国际酒店;
大整数结果;
System.out.println(“计算因子”);
而(!valeurRecu.contentEquals(“q”)){
System.out.println(“计算者(q-退出者):”;
扫描仪中心=新扫描仪(System.in);
valeurRecu=entre.nextLine();
如果(valeurRecu.contentEquals(“q”))entre.close();
否则{
试一试{
valeur=Integer.parseInt(valeurRecu);
}捕获(数字格式){
System.out.println(“Pas-un-entier.Essayer-encore.\n”);
继续;
} 
试一试{
结果=事实(valeur);
if(resultat.compareTo(BigInteger.valueOf(-1))==0){
System.out.println(“Valeur negative.Essayer encore.\n”);
}
else System.out.println(“Factoriel”+valeur+”->“+fact(valeur)+”\n”);
}捕获(堆栈溢出错误e){
System.out.println(“从桩上拆下。整个文件加上小文件。\n”);
继续;
}
}
}
System.out.println(“Au revoir!:)\n”);
}
公共静态void main(字符串[]args){
runBigFact();
}
}
我已经读到Java8支持尾部调用优化,但我认为我一定没有正确地实现它

那你看错了。或者,你读了一个正确的陈述,但没有正确地解释它

Java语言不支持尾部调用递归。从来没有。它可能永远不会

然而,虚拟机java有一些特性,使其他非java语言更容易编译成类文件在java运行时上运行,以支持TCO。这大概就是你读到的

我只是在寻找任何关于如何使用真正的尾部调用优化、lambda表达式或我能做的任何事情的建议

用scala或类似的语言编写

说真的,java怎么没有TCO??? TCO是昂贵的:Java有这样一条规则:当发生错误时,您会得到一个堆栈跟踪,而堆栈跟踪是一个定义良好的概念,至关重要的是,每个逻辑调用跟踪一个堆栈帧。如果存在TCO,则此无法继续。当然,也有一些选择:堆栈上的每个单独帧都可以获得一个“计数器”,这样堆栈跟踪在正确表示“并且该调用序列已重复8190581次”的同时,仍然保持较小的内存占用。这也是lang规范中关于它如何工作、何时起作用和不起作用以及这一切意味着什么的一大堆文本,规范中的任何附加页面都是永远的维护负担——这不是“将TCO添加到java中是绝对优越的”,所以当我们着手解决它时,扣篮,任何具有该功能的拉取请求都将立即集成”

此外,TCO作为一种模式是一种做事的方式,但它不是唯一的方式。对于任何可以编写为TCO递归应用程序的应用程序,将其重构为基于循环的非递归算法通常并不那么困难。比如说,与基于产量的异步操作不同,在异步操作中,您当然可以重写(嘿,这都是图灵机器),但是重写会很困难,并且生成的代码也很难理解。我不想讨论屈服/异步风格编码的价值(或缺乏价值),只是指出TCO没有“啊,但是,如果TCO是一个好主意,那么只有TCO会做”这样的外表

我手头没有这些链接,但是那些对java的未来有很大影响的人已经说过这种说法,比如Brian Goetz、Mark Reinhold等。如果你真的致力于尝试将其添加到java中,我建议你在网上搜索这些陈述,然后尝试形成一些论据,专门解决它们所陈述的问题。因为如果你不能说服那些人,那就永远不会发生

那么我在java中做什么呢? 不要使用递归;在时使用
,或在
时使用

更新:那篇博文呢? 在您链接到的评论中。那是。。不是TCO

这就是使用lambdas编写一个框架,让您或多或少地模拟TCO,但它不是TCO。博客描述了一个小小的框架——因此,哟
public static void main(String[] args) {
    count = 0;
    long n = 14000;
    simpleLong(n);
    factoriel(BigInteger.valueOf(n));
    
}
    
static BigInteger factoriel(BigInteger n) {
    if (n.compareTo(BigInteger.TWO) == 1) {
        return factoriel(n.subtract(BigInteger.ONE)).multiply(n);
    }
    return n;
}
    
static long simpleLong(long n) {
    if (n > 1) {
        simpleLong(n-1);
    }
    return n;
}