# Unveraenderliche Klasse - Collatz Problem



## donsao (8. Mai 2012)

So juten Abend freunde 

Ich habe hier eine Aufgabenstellung und komme partout nicht weiter, vllt. kann mir ja jemand von euch weiterhelfen.



> Die Klasse Collatz repräsentiert eine solche Zahlenfolge.
> Der Konstruktor legt den Startwert fest,
> die Methode getNumber liefert die aktuelle Zahl und next wechselt zur nächsten Zahl.
> Schließlich gibt isInLoop Auskunft darüber, ob der (vermutlich einzige)
> ...



Hier ist der Collatz und der Collatz Main Code.


```
public class Collatz
{
	/** Die aktuelle Zahl der Folge. */
	private int number;

	/** Ctor zum Start einer neuen Folge.
	 * @param number Erste Zahl der Folge.
	 */
	public Collatz(final int number)
	{
		this.number = number;
	}

	public int getNumber()
	{
		return number;
	}

	/** Wechselt zur nächsten Zahl der Folge.
	 */
	public void next()
	{
		if(number % 2 == 0)
			number /= 2;
		else
			number = 3 * number + 1;
	}

	/** Gibt Auskunft, ob die Folge in einem Zyklus steckt,
	 * das heißt, ab jetzt nur noch Zahlen liefert, die schon
	 * früher geliefert wurden.
	 * @return true = Folge läuft in einer Schleife; false andernfalls.
	 */
	public boolean isInLoop()
	{
		return number == 1 || number == 2 || number == 4;
	}

}
```


```
public class CollatzMain
{
	/** Hauptprogramm.
	 * @param args Kommandozeilenargumente.
	 * Erste Zahl der Folge.
	 * Alle weiteren bis zum Erreichen eines Zyklus werden ausgegeben.
	 */
	public static void main(final String... args)
	{
		final Collatz collatz = new Collatz(Integer.parseInt(args[0]));
		while(!collatz.isInLoop())
		{
			collatz.next();
			System.out.println(collatz.getNumber());
		}
	}

}
```

Nun habe ich die Objektvariable Number als final deklariert, und hab Collatz Next wie folgt veraendert.


```
public Collatz next()
	{
		int n = number;
		if(n % 2 == 0)
			n /= 2;
		else
			n = 3 * n + 1;
		Collatz result = new Collatz(n);
		return result;
	
	}
```

Nun weiss ich leider nicht weiter wie ich bei "isInLoop" nun auf dieses neue n zugreifen kann, da es mit number ja nichtmehr funktioniert.
Ich hoffe mir kann jemand helfen, vielen Dank schonmal dafuer


----------



## nillehammer (8. Mai 2012)

> Nun weiss ich leider nicht weiter wie ich bei "isInLoop" nun auf dieses neue n zugreifen kann, da es mit number ja nichtmehr funktioniert.
> Ich hoffe mir kann jemand helfen, vielen Dank schonmal dafuer


Fachlich habe ich zwar offen gestanden nicht verstanden, was dahinter steckt, aber programmiertechnisch müsstest Du in _isInLoop()_ die Methode _next()_ aufrufen


----------



## donsao (8. Mai 2012)

Es geht auch nur um diese Umstellung auf eine unveraenderliche Klasse, das ganze hat irgendwas mit dieser Collatz-Folge zu tun, welcher aber nicht wirklich relevant (da Formel schon gegeben) ist.

Das hatte ich auch schon probiert, bloss next() hat ja als return-Wert ein Collatz-Typ und kein Int-Typ, weswegen die Boolean Vergleiche dann nicht hinhauen.

EDIT: Nun gebe ich int n als return Wert bei der Next-Methode zurueck, womit "isInLoop" nun auch funktioniert.
Nur leider ist nun das Problem das mein n immer wieder mit number ueberschrieben wird und daher logischerweise jedes mal das selbe Ergebnis rauskommt.


----------



## SlaterB (8. Mai 2012)

ein neues Collatz-Objekt zurückzugeben klingt schon richtig im Sinne unveränderlicher Objekte, dort kann man dann ja die neue Number abfragen

was dich an isInLoop() zögern läßt ist nicht verständlich,
für das alte Collatz-Objekt arbeitet die Methode nach dem next()-Aufruf wie zuvor, das ist auch richtig so,
für das neue Collatz-Objekt wird selbstverständlich das neue n, das dann dortige number angeschaut,
arbeitet also wie nach dem next()-Aufruf in der alten Klasse, das ist doch auch gut

das scheint mir also ohne noch nötige Veränderung genausogut wie vorher zu funktionieren

-------

man könnte überlegen, die Funktionalität dieser Methode grundsätzlich aufzubohren, 

sie erkennt nur 1, 2, 4,  wenn eine solche Zahl einmal da war, die Methode vielleicht gar ausgeführt wurde und true zurückgegeben hat,
und auf die alte oder neue Weise zu einer anderen Zahl in der Folge gewechselt wird,
dann gibt die Methode wieder nur false zurück, merkt sich nicht dass nun dauerhaft in einer Schleife vorhanden

dafür könnte man, wenn man will, einen boolean einfügen, in der alten Klasse schnell gemacht,
bei dem neuen unveränderlichen Ansatz müsste man darauf achten, 
1) diese Eigenschaft sofort im Konstruktor zu berechnen, darf sich nicht später verändern,
wobei man darüber streiten kann ob nicht Berechnung erst vor erstmaliger Rückgabe ausreicht,
hängt ja nur von unveränderlichen Daten ab
2) wichtig ist noch, dass der boolean dann, falls einmal true, an weitere neue next-Objekte übergeben wird,
denn die könnten mit anderen Zahlen als 1, 2, 4 ja nicht mehr selber wissen ob schon eine Schleife festgestellt wurde

wie gesagt nur falls man insgesamt will, dass diese Information erhalten bleibt,
falls die erste gepostete Klasse vorgegeben war, dann dort nicht vorhanden und anscheinend nicht nötig


----------



## donsao (8. Mai 2012)

Ich verstehe leider immer noch nicht ganz, warscheinlich steh ich richtig aufm Schlauch .

Ich versuche durch 


```
public boolean isInLoop()
	{
		return  number.next() == 1 || number.next() == 2 || number.next() == 4;
	}
```

das neue n mit den verschiedenen Zahlen zu vergleichen, doch bekomme stets die Fehlermeldung

mein Collatz Next sieht inzwischen wieder so aus 


```
public Collatz next()
	{
		int n = number;
		if(n % 2 == 0)
			n /= 2;
		else
			n = 3 * n + 1;
		Collatz result = new Collatz(n);
		return result;
	
	}
```



> Cannot invoke next() on the primitive type int	Collatz.java	/Collatz/src	line 35	Java Problem



Vllt. stelle ich mich auch einfach nur etwas bloed an. ^^


----------



## SlaterB (8. Mai 2012)

next() ist eine Methode von Collatz, kann also nicht an number aufgerufen werden, höchstens an this, am eigenen Objekt,
in der Hinsicht ist bloed wahrlich eine richtige Bezeichnung, wenn man das sagen darf  ,

noch grundsätzlicher ist aber die Frage, warum du überhaupt irgendwas mit next() in dieser Methode versucht?
steht in dessen Beschreibung dass sie die nächste Zahl in der Folge untersuchen soll?
das hat sie doch vorher auch nicht gemacht, isInLoop() ist unverändert eine korrekte Methode 
oder was genau stört dich am Verhalten von isInLoop(), wenn du die Methode NICHT kaputt machst sondern wie vorher beläßt?

wie gesagt hat das von next() erzeugte neue Collatz-Objekt eine neue number, 
dort liefert der isInLoop() vielleicht ein anderes Ergebnis als im alten Collatz-Objekt,
das ist alles gut so, ohne dass du auch nur eine Zeile programmieren musst


----------



## Marco13 (8. Mai 2012)

Nur überflogen, aber... warum sollte an isInLoop überhaupt was geändert werden? Auch die Immutable klasse hat doch das field "number"?!


----------



## Landei (8. Mai 2012)

[c]next[/c] lässt sich auch ganz ohne veränderliche Variablen schreiben:

```
public Collatz next() {
        return new Collatz( number % 2 == 0 ? number / 2 : 3 * number + 1);
    }
```

Allerdings musst du mit dem Ergebnis auch etwas *tun*:


```
public static void main(final String... args) {
        Collatz collatz = new Collatz(Integer.parseInt(args[0]));
        while(!collatz.isInLoop())
        {
            collatz = collatz.next(); 
            System.out.println(collatz.getNumber());
        }
    }
```

Kaum macht man es richtig, geht's...


----------



## Landei (8. Mai 2012)

Interessanterweise lässt sich die "unveränderliche" Version auch fast 1:1 nach Haskell übersetzen - nur die while-Schleife des Hauptprogramms muss etwas umformuliert werden.


```
data Collatz = Collatz { getNumber :: Int }

isInLoop (Collatz n) = n `elem` [1,2,4]

next (Collatz n) = Collatz $ if even n then n `div` 2 else 3*n+1 

main = print $ map getNumber $ takeWhile (not.isInLoop) $ iterate next (Collatz 27)
```


----------



## donsao (8. Mai 2012)

Wow, im Prinzip hing es bei mir nur an diesem 


```
collatz = collatz.next();
```

in der Main Methode. Danach hatte ich viel zu kompliziert gedacht.


Vielen vielen Dank


----------

