# Multiplikations-Tabelle - Elegantere Lösung möglich?



## Private Void (19. Dez 2009)

Hallo!

Eine Übungsaufgabe, die ich mal gemacht hab, lautete, eine "Multiplikations"-Tabelle ausgeben zu lassen, in der die Ergebnisse der Multiplikation zweier Zahlenbereiche (z.B die Zahlen 6 bis 23 multipliziert mit den Zahlen 12 bis 58) aufgeführt sind.
Das größte vorhande Produkt darf aber nicht vierstellig werden, muss also unter 1000 bleiben.
Desweiteren durfte man sich auf natürliche Zahlen beschränken.

Es folgt meine eigene Lösung und ich frage euch, ob es evtl. eine bessere/elegantere/kürzere Lösung gibt.
Ich hab berücksichtigt, dass der Anwender evtl. falsche Eingaben macht und hab es beim Testlauf ziemlich ausgereizt. Bei einem Fall gab das Programm dieselbe Tabelle *zweimal* aus! Ich finde aber den Punkt nicht, an dem sich das verdoppelt.

Zur besseren Übersicht hab ich JavaDoc mit einfließen lassen und wollte wissen, ob ich das vielleicht auch besser machen könnte.

Wenn es von Bedeutung ist: ich habe 'Eclipse' dafür verwendet.

PS: Ich finde es schaut länger aus, als es ist, also bitte nicht erschrecken!


```
/**
 * @author 'Private Void' (Nickname auf java-forum.net)
 * @version 1.0 (19.12.2009)
 */

/** 
 * Ich verlagere gern die main-Methode in eine separate Klasse,
 * um in der anderen 'static'-Methoden zu vermeiden
 */
final class Start {
	
	/**
	 * Es erstellt ein Objekt der anderen Klasse, um damit die
	 * erste Methode aufzurufen
	 * @param args hat im Grunde nichts weiter zu bedeuten
	 */
	public static void main(String[] args) {
		Ausgabe start = new Ausgabe();
		start.Eingabe();
	}
}
```


```
import java.util.Scanner;

/**
 * Kontrolle, ob die Zahleneingaben der Anforderungen entsprechen
 * Mittels for-Schleifen wird nacheinander jede einzelne Zeile der Tabelle generiert
 */
final class Ausgabe {
	
	int smin, smax, zmin, zmax;

	/**
	 * Leerer Konstruktor
	 * @see main-Methode
	 */
	protected Ausgabe() {

	}
	
	/**
	 * Für jeden einzelnen Wert wird eine eigene Methode aufgerufen
	 * Bei jedem Zahlenpaar wird kontrolliert, ob die Eingabe in Ordnung ist
	 */
	protected void Eingabe() {
		System.out.println("waagrerechter Zahlenbereich");
		smin = SpaltMin();
		smax = SpaltMax();
		while (smin > smax) {
			System.out.println("Die erste Zahl muss kleiner sein als die zweite!");
			smin = SpaltMin();
			smax = SpaltMax();
		}
		
		System.out.println("senkrechter Zahlenbereich");
		zmin = ZeilMin();
		zmax = ZeilMax();
		while (zmin > zmax) {
			System.out.println("Die erste Zahl muss kleiner sein als die zweite!");
			zmin = ZeilMin();
			zmax = ZeilMax();
		}
		
		if (smax * zmax > 999) {
			System.out.println("Die größte Zahl der Wertemenge darf höchstens drei Dezimal-Stellen haben!");
			Eingabe();
		}
		
		Tabelle(smin, smax, zmin, zmax);
	}
	
	/**
	 * @exception behebt Fehler durch Eingaben außerhalb des Datentyps 'int'
	 * @return waagerechter Minimalwert
	 */
	private int SpaltMin() {
		Scanner in = new Scanner(System.in);
		try {
			System.out.println("Von:");
			smin = in.nextInt();
		} catch (Exception e) {
			System.out.println("int-Zahl eingeben!");
			SpaltMin();
		}
		return smin;
	}
	
	/**
	 * @exception behebt Fehler durch Eingaben außerhalb des Datentyps 'int'
	 * @return waagerechter Maximalwert
	 */
	private int SpaltMax() {
		Scanner in = new Scanner(System.in);
		try {
			System.out.println("Bis:");
			smax = in.nextInt();
		} catch (Exception e) {
			System.out.println("int-Zahl eingeben!");
			SpaltMax();
		}
		return smax;
	}
	
	/**
	 * @exception behebt Fehler durch Eingaben außerhalb des Datentyps 'int'
	 * @return senkrechter Minimalwert
	 */
	private int ZeilMin() {
		Scanner in = new Scanner(System.in);
		try {
			System.out.println("Von:");
			zmin = in.nextInt();
		} catch (Exception e) {
			System.out.println("int-Zahl eingeben!");
			ZeilMin();
		}
		return zmin;
	}
	
	/**
	 * @exception behebt Fehler durch Eingaben außerhalb des Datentyps 'int'
	 * @return senkrechter Maximalwert
	 */
	private int ZeilMax() {
		Scanner in = new Scanner(System.in);
		try {
			System.out.println("Bis:");
			zmax = in.nextInt();
		} catch (Exception e) {
			System.out.println("int-Zahl eingeben!");
			ZeilMax();
		}
		return zmax;
	}
	
	/**
	 * Erstellt nacheinander jede einzelne Zeile der Tabelle
	 * @param smin, smax, zmin und zmax von der Eingabe
	 */
	private void Tabelle(int smin, int smax, int zmin, int zmax) {
		int a = smax - smin + 1;
		int b = zmax - zmin + 1;
		
		System.out.print("       ");
		
		for (int i = 0; i < a; i++) {
			int c = smin + i;
			if (c < 10) {
				System.out.print("   "+c);
			}
			else {
				System.out.print("  "+c);
			}
		}
		
		System.out.println("");
		System.out.print("        ");
		for (int i = 0; i < a; i++) {
			System.out.print("----");
		}
		System.out.println("");

		for (int i = 0; i < b; i++) {
			int c = zmin + i;
			
			if (c < 10) {
				System.out.print("  "+c+"  |");
			}
			else {
				if (c < 100) {
					System.out.print(" "+c+"  |");
				}
				else {
					System.out.print(c+"  |");
				}
			}
			
			System.out.print(" ");
			
			for (int j = 0; j < a; j++) {
				int d = smin + j;
				int e = c * d;
				
				if (e < 10) {
					System.out.print("   "+e);
				}
				else {
					if (e < 100) {
						System.out.print("  "+e);
					}
					else {
						System.out.print(" "+e);
					}
				}
			}
			System.out.println("");
		}
	}
}
```


----------



## nrg (22. Dez 2009)

ich find das vom Aufbau her ganz schön... jetzt auf den ersten Blick wüsste ich auch nicht in welchem case es 2x ausgibt.
Vielleicht ein kleiner Stilfehler: Man schreibt methoden() klein. Konstruktoren und Klassennamen, wie bei dir schon richtig gemacht, groß.

grüße

nrg

edit: ich persönlich hätte jetzt den Klassennamen und den einen oder anderen Methodennamen etwas aussagekräftiger gestaltet. Aber das ist denke eher individueller stil.


----------



## Marco13 (22. Dez 2009)

Ja, ich hätte auch nicht durch "Draufschauen" die Fehlerursache erkannt, und fand es insgesamt auch OK. Lediglich die Formatierung könnte man evtl. geschickter machen. Also sowas wie

```
if (c < 10) {
                System.out.print("   "+c);
            }
            else {
                System.out.print("  "+c);
            }
```
taucht halt in ähnlicher Form mehrfach auf, und das ist eigentlich unschön. Man könnte mit der Methode String#format vermutlich einiges davon vereinfachen. Und das ganze ggf. so flexibel, dass es eine Konstante wie

```
private static final int MAX_PRODUCT_DIGITS = 3; // Für Produkte < 1000
```
gibt - oder sogar eine nicht-Konstante....


----------



## Private Void (22. Dez 2009)

Warum es nach einer bestimmen falschen Eingabe die Tabelle zweimal ausgibt, hab ich mittlerweile herausgefunden:
In Zeile 47 muss uch um den Ausdruck eine else-Klammer rummachen - quasi so:


```
...

        if (smax * zmax > 999) {
            System.out.println("Die größte Zahl der Wertemenge darf höchstens drei Dezimal-Stellen haben!");
            Eingabe();
        }
        else {
            Tabelle(smin, smax, zmin, zmax);
        }
    }

    ...
```

@Marco13:
Natürlich macht es Sinn den Quelltext möglichst kurz zu halten.
Mein Dozent erzählt uns immer, es gibt zwei Prinzipien in der Programmierung: zum einen 'Information Hiding' ("so private wie möglich, so public wie nötig") und Faulheit, sprich so wenig Schreibarbeit wie möglich - also nach Möglichkeit mehrere Aspekte eines Programms, die sehr ähnlich oder gleich sind, zu einer Methode zusammenfassen und an entsprechender Stelle mit passenden Übergabeparametern aufrufen.
Ich muss noch schauen, ob ich es hinbekomme, den Quellcode so anzupassen, wie du es vorgeschlagen hast


----------



## nrg (22. Dez 2009)

Private Void hat gesagt.:


> Warum es nach einer bestimmen falschen Eingabe die Tabelle zweimal ausgibt, hab ich mittlerweile herausgefunden:
> In Zeile 47 muss uch um den Ausdruck eine else-Klammer rummachen - quasi so:



achsooo, den rekursiven aufruf der eingabe() Methode hab ich net gesehn. hab nur geschaut, ob öfters tabelle() aufgerufen wird bzw, ob um tabelle() eine Schleife rum ist.

grüße


----------



## Private Void (22. Dez 2009)

Ich schau mir mal die Erstellung von GUIs mittels Swing an, dann kann ich das in einem eigenen Programmfenster ablaufen lassen - was natürlich alle meine bisherigen Java-Erzeugnissen noch etwas aufwerten würde


----------



## Private Void (7. Feb 2010)

Ich hab jetzt mal mein schon ein paar Monate altes Programm ausgegraben und versucht zu verbessern. Könnte jemand ein Statement abgeben, ob mir das gelungen ist und ob es vielleicht noch irgendwo was zu verbessern geben könnte

[Java]
import java.util.Scanner;

public class Multiplikationstabelle {

	// Erstellen eines Objekts der eigenen Klasse, um static-Methoden zu umgehen (is mir lieber so)
    public static void main(String[] args) {
        Multiplikationstabelle start = new Multiplikationstabelle();
        start.eingabe();
    }
    public Multiplikationstabelle(){}

    int a, b, c;

    /* Diese Methode ruft nacheinander mehrere andere Methoden auf,
     * die auf fehlerhafter Eingabe mit einer Rekursion reagieren
     */
    private void eingabe() {
        spaltstart();
        zeilstart();
        while(a*b>99999999){
            System.out.println("Werte zu groß");
            spaltstart();
            zeilstart();
        }
        do{
            groesse();
        }while(c<1||c>30);
        tabelle(a, a+c-1, b, b+c-1);  // '-1' weil sonst nicht c, sondern c+1 Werte pro Zeile bei rauskommen
    }

    // Startwert für waagerechten Zahlenbereich
    private int spaltstart() {
        System.out.println("Startwert Spalte:");
        try{
            Scanner in = new Scanner(System.in);
            a = in.nextInt();
        }catch(Exception e){
            System.out.println("eine natürliche Zahl!");
            spaltstart();
        }
        if(a<1){     // if-Block nachträglich hinzugefügt
            spaltstart();
        }
        return a;
    }

    // Startwert für senkrechten Zahlenbereich
    private int zeilstart() {
        System.out.println("Startwert Zeile:");
        try{
            Scanner in = new Scanner(System.in);
            b = in.nextInt();
        }catch(Exception e){
            System.out.println("eine natürliche Zahl!");
            zeilstart();
        }
        if(b<1){     // if-Block nachträglich hinzugefügt
            zeilstart();
        }
        return b;
    }

    // Länge der Zahlenbereiche
    private int groesse() {
        System.out.println("Größe der Tabelle (bis 30):");
        try{
            Scanner in = new Scanner(System.in);
            c = in.nextInt();
        }catch(Exception e){
            System.out.println("eine natürliche Zahl!");
            groesse();
        }
        return c;
    }

    private void tabelle(int smin, int smax, int zmin, int zmax) {

    	/* ERSTE ZEILE */
    	// Ausgabe der Angabewerte inkl. Länge der Zwischenräume in der ersten Zeile
        System.out.print("   ");

        // je länger die senkrechten Zahlen desto mehr Platz nach links
        for (int i = 0; i < Math.log10(zmax)+1; i++) {
            System.out.print(" ");
        }

        /* Wenn die kleineren Zahlen des waagerechten Bereichs
         * weniger Stellen haben als die größeren,
         * werden die Lücken davor umso größer
         * Ausgabe der Zahlen in der ersten Zeile
         */
        for (int i = 0; i <= smax - smin; i++) {
        	// Orientierung der Zwischenräume an der größten unter den Ergebnissen vorkommende Zahl
            if((int)Math.log10(smin + i) < (int)Math.log10(smax*zmax)) {
                for (int j = 0; j < (int)Math.log10(smax*zmax) - (int)Math.log10(smin+i); j++) {
                    System.out.print(" ");
                }
            }
            System.out.print((smin+i)+"  ");
        }
        System.out.println();
        /* ERSTE ZEILE ferig*/

        /* TRENNSTRICH zwischen Angabe und Ergebniswerten */
        System.out.print("  ");
        for (int i = 0; i < Math.log10(zmax)+1; i++) {
            System.out.print(" ");
        }
        for (int i = 0; i < (smax-smin+1); i++) {
            for (int j = 0; j < (int)Math.log10(smax*zmax)+3; j++) {
                System.out.print("-");
            }
        }
        /* TRENNSTRICH fertig */

        /* MONSTER-FOR-SCHLEIFE
         * Ab jetzt wirds interessant ;-)
         * drei for-Schleifen ineinander!
         */
        for (int i = 0; i < zmax-zmin+1; i++){
            System.out.println(); // Zeilenwechsel

            /* falls die kleineren Zahlen des senkrechten Zahlenbereichs
             * weniger Stellen haben als die größeren, wird erstmal
             * dementsprechend Platz nach links gelassen
             */
            if((int)Math.log10(zmin + i) < (int)Math.log10(zmax)) {
                for (int j = 0; j < (int)Math.log10(zmax) - (int)Math.log10(zmin + i); j++) {
                    System.out.print(" ");
                }
            }
            System.out.print((zmin+i)+" |"); // inkl. Trennstrich zwischen Angabe und Ergebniswerten


            for (int j = 0; j <= smax - smin; j++) {
            	System.out.print("  "); 	// Grundabstand von 2 Leerzeichen
                int e = (smin+j)*(zmin+i); 	// Berechnung der einzelnen Ergebniswerte

                /* Falls der momentane Wert weniger Stellen hat als das größe Ergebnis
                 * werden Leerzeichen hinzugefügt
                 */
                if((int)Math.log10(e) < (int)Math.log10(smax*zmax)){
                    for (int k = 0; k < (int)Math.log10(smax*zmax) - (int)Math.log10(e); k++) {
                        System.out.print(" ");
                    }
                }
                System.out.print(e); // schließlich Ausgabe des momentanen Werts
            }
        }
        /* MONSTER-FOR-SCHLEIFE Ende */
    }
}
[/Java]


----------



## Firestorm87 (7. Feb 2010)

Ich habe noch nie so viele Schleifen hintereinander gesehen, die man ohne auch nur einen Kommentar interpretieren sollte 

Sorry, bin ja sonst für sprechende Methoden und Variablenbezeichnungen, aber hier würden 1-2 erklärungen einem Fremden beim lesen dann doch helfen..


----------



## Private Void (7. Feb 2010)

Ok ich seh's ein und hab Kommentar ergänzt!
Ich hoffe es bringt den potentiellen Leser ein Stückchen weiter!


----------

