---
title: 'Die Java 8 JVM wird keine Tail Call Recursion Optimierung bekommen'
url: 'https://www.tutego.de/blog/javainsel/2013/06/die-java-8-jvm-wird-keine-tail-call-recursion-optimierung-bekommen'
markdown: 'https://www.tutego.de/blog/javainsel/2013/06/die-java-8-jvm-wird-keine-tail-call-recursion-optimierung-bekommen.md'
date: '2013-06-17'
description: 'Endrekursion (engl. Tail Call Recursion) ist eine Besonderheit bei Methoden, dass sie mit einem rekursiven Aufruf enden. Zum Einstieg: Ist die bekannte rekursive Implementierung der Fakultät endrekursiv? int factorial(int n) { if ( n == 0 ) return 1; return n * factorial( n – 1 ); } Zwar sieht …'
taxonomy:
  category:
    - 'Java 8'
---

# Die Java 8 JVM wird keine Tail Call Recursion Optimierung bekommen

![Illustration einer tropischen Insel mit Palmen und einem hohen Berg](https://www.tutego.de/blog/javainsel/user/themes/tutego/images/insel-cover.jpg)# Java Blog für Programmierer

[Java Blog für Programmierer](https://www.tutego.de/blog/javainsel/)

## Die Java 8 JVM wird keine Tail Call Recursion Optimierung bekommen

17.06.2013 · [Christian Ullenboom](https://www.tutego.de/blog/javainsel/author/admin/)

**Endrekursion** (engl. **Tail Call Recursion**) ist eine Besonderheit bei Methoden, dass sie mit einem rekursiven Aufruf enden. Zum Einstieg: Ist die bekannte rekursive Implementierung der Fakultät endrekursiv?

```java
int factorial(int n) {
  if ( n == 0 ) return 1;
  return n * factorial( n – 1 );
}
```

Zwar sieht es optisch so aus, als ob die `factorial(int)` mit einem Methodenaufruf an `factorial(…)` endet, doch findet hier keine Endrekursion statt, da nach dem Methodenaufruf noch eine Multiplikation stattfindet – etwas umgeschrieben ist es besser zu erkennen:

```java
int factorial(int n) {
  if ( n == 0 ) return 1;
  int fac = factorial( n – 1 );
  return n * fac;
}
```

Die Berechnung der Fakultät lässt sich umschreiben, so dass tatsächlich eine Endrekursion sattfindet, und zwar durch Einführung eines Containers für Zwischenergebnisse, genannt Akkumulator:

```java
int factorial( int n )
{
  return factorialTailrec( n, 1 );
}

private int factorialTailrec( int n, int accumulator )
{
  if (n == 0) return accumulator;
  return factorialTailrec( n – 1, n * accumulator );
}
```

Die umgeschriebene Version büßt gegenüber der ursprünglichen Version an Schönheit ein. Doch endrekursive Aufrufe sind attraktiv, da eine schlaue Übersetzungseinheit sie so optimieren kann, dass der rekursive Methodenaufruf durch einen Sprung ersetzt wird. In der Java Sprache haben wir keine direkten Sprünge, doch im Bytecode schon, sodass die Basis der Optimierung im Grunde so aussehen kann:

```java
private int factorialTailrec( int n, int accumulator ) {

```

```java
start:
```

```java
  if ( n == 0 ) return accumulator;
```

```java
  accumulator *= n;
```

```java
  n--;
```

```java
  goto start;
```

```java
}
```

`Die Rekursion ist durch eine ordinäre Schleife ersetzt, was Stack einspart und eine sehr gute Performance ergibt.`

`In funktionalen Programmen ergeben sich eher Situationen, in denen Endrekursion vorkommt, sodass es attraktiv ist, diese zu optimieren. Die Standard-JVM kann das bisher nicht, weil Java traditionell keine funktionale Programmiersprache ist, und Endrekursion eher selten vorkommt. Zwar wird die Optimierung von Endrekursion (engl. tail call optimization) immer wieder diskutiert und auch schon in ``Prototypen ausprobiert, aber nie  von der Oracle JVM implementiert. ``Für Entwickler heißt dass, rekursive Aufrufe nicht umzuschreiben in endrekursive Varianten, da sie sowieso nicht optimiert werden und nur unleserlicher würden, und bei großen Datenvolumen, sprich Stack-Tiefe, auf die übliche nicht-rekursive iterative Version umzustellen. Im Fall von factorialTailrec(..) kann dies nämlich auch vom Entwickler gemacht werden und sieht so aus:`

```java
private int factorialTailrec( int n, int accumulator ) {

while (n != 0) {

accumulator *= n;

n–;

}

return accumulator;

}
```

` `

Kategorien: [Java 8](https://www.tutego.de/blog/javainsel/category/java-8/)

## 3 Kommentare

**Christian Ullenboom** · [13.02.2016 09:33](#comment-360087) · [Antwort auf einen Kommentar](#comment-357333)

Arrrrrg, Mist! Natürlich, das Label muss höher. Danke!

**Anon** · [12.02.2016 12:32](#comment-357333)

Guter Artikel -- kurz und verständlich. Es hats sich jedoch ein Fehler eingeschlichen. Der gezeigte Bytecode mit dem goto würde nur für n==0 terminieren. Das Label "start:" muss eine Zeile nach oben, also über das if, geschoben werden.

**Johannes** · [04.05.2014 14:55](#comment-13847)

'Scala' wäre eine Alternative. Der Scala-Compiler übersetzt endrekursive Funktionen zu Schleifen. Zudem gibt es eine Annotation @tailrec, bei der der Compiler dann sich beschwert, wenn die Funktion doch nicht endrekursiv ist.

Die bisherigen Kommentare wurden aus WordPress übernommen. Neue Kommentare sind derzeit geschlossen.

[← Alle Beiträge](https://www.tutego.de/blog/javainsel/)

---

## Navigation

- Previous: [Einmal Finalizer, vielleicht mehrmals die automatischen Speicherbereinigung](https://www.tutego.de/blog/javainsel/2013/06/einmal-finalizer-vielleicht-mehrmals-die-automatischen-speicherbereinigung.md)
- Next: [NetBeans 7.3.1 auch mit Java EE 7 Unterstützung](https://www.tutego.de/blog/javainsel/2013/06/netbeans-7-3-1-auch-mit-java-ee-7-untersttzung.md)
