Variable in for Schleife ansprechen ohne Array ?

tollewurst

Mitglied
Hallo,

ich habe folgendes Problem.
Ich habe z.b. Variablen

String var0="Text 0";
String var1="Text 1";
String var2="Text 2";
String var3="Text 3";

Jetzt möchte ich eine for Schleife, die das ohne Array ausgibt. Geht das ?

for(int i=0;i<=3;i++){
System.out.println( var+i );
}

wie ersetze ich das var+i,
dass eben
Text0
Text1
Text2
Text3
usw. ausgeben wird.

In Android geht das ja mit der String.xml so
Integer id = context.getResources().getIdentifier("var" + i, "string", context.getPackageName());
String name = context.getString(id);

Aber wie geht das in purem Java ohne Android ?
 
Hm...du versuchst gerade, dem Pferd das Zaumzeug über den Schweif zu ziehen.

Erstmal: Warum willst du es denn nicht mit einem Array machen?
Und dann würde ich dir dringend raten, auf Variablennamen wie "varx" zu verzichten. Das wird scheußlicher Code, in dem auch du selbst dich bald nicht mehr zurechtfinden wirst. Spätestens, wenn du eine Zeit lang etwas anderes machst nicht mehr.

Ansonsten: weder den Computer noch die JVM interessieren die Bezeichnungen der Variablen, die sind nach dem Kompilieren Geschichte. Insofern würde ich sagen, daß dein Vorhaben nicht möglich ist (wobei ich mich da gbf. gerne eines Besseren belehren lasse).
 
Jetzt möchte ich eine for Schleife, die das ohne Array ausgibt. Geht das ?
Der gute Ratschlag: Halte Daten so vor, dass die Zugriffe, die Du brauchst, möglich sind! Keine wilden Workarounds. Wenn es Dein Code (Deine Variablen) sind, dann mach daraus ein Array. Das nennt sich Refactoring.

Selbst wenn ein Zugriff über den Namen möglich wäre (z.B. Zugriff auf Instanzvariablen über Reflection): Das ist nicht der Weg!
In Android geht das ja mit der String.xml so
Integer id = context.getResources().getIdentifier("var" + i, "string", context.getPackageName());
String name = context.getString(id);
Da hast Du aber keine einzelnen Variablen! Da wurde auch eine entsprechende Datenstruktur geschaffen, die die notwendigen Operationen liefert!

Da bei Android hast Du eine Instanz der Klasse Context: https://developer.android.com/reference/android/content/Context (bzw. eine Klasse, die davon abgeleitet wurde!)
getResources gibt eine Instanz der Klasse Ressources zurück: https://developer.android.com/reference/android/content/res/Resources

Und da wird dann auf die Ressourcen zugegriffen. Wie da dann gearbeitet wird, könnte man sich im Source anschauen. Evtl. werden Dateien gelesen und dann als Map gespeichert. Wenn Du über Keys auf Werte zugreifen können willst, dann kannst Du eine Map verwenden.
 
Sagen wir so, ich schreibe die Logik immer in IntelliJ, weil der Compiler da schneller ist. Und dann exportiere ich den Algorithmus nach Android.

Siehe mein Android Beispiel, da liegen die Variablen auch nicht im Array, sondern in einer xml, die dann in mehrere Sprachen übersetzt wird.
Und da kann man sich auch eine id holen und dann darüber ansprechen. Wie die Variablen heißen, spielt erstmal keine Rolle, ich wollte es so einfach wie möglich haben. Weil dann kann ich, falls das geh ja einfach alles umschreiben.

In Android spricht man ja zur Not oder anders den String mit R.string.var1 an.
Daher habe ich in Java eigentlich einen Klasse die string heißt.

Sprich, ich programmiere die Logik einfach mit string.var1 durch.
und wenn ich dann wieder in Android bin, sage ich einfach suchen/ersetzen string. -> R.string.

Nur darum geht es eigentlich. Warum ich wissen will ob man die Variablen auch so ansprechen kann.

Also eigentlich
class Strings{
String var0="Text 0";
String var1="Text 1";
String var2="Text 2";
String var3="Text 3";
}

Strings string = new Strings();

for(int i=0;i<=3;i++){
System.out.println( string.var+i );
}
 
Okay, es sind also Instanzvariablen.
Wie @kneitzel schon schrieb: Es geht mit Reflection, aber ist nicht das, was du willst bzw. tun solltest.
Die Warnung nur vorweg, es würde gehen mit:
Java:
String derWert = (String) Strings.class.getDeclaredField("var" + i).get(string);
 
Also vom Prinzip her brauche ich nur in Java die strings.xml und will das genau so ansprechen. Sprich Texte auslagern.
Aber habe noch nicht gefunden, wie das geht.
 
Array ist ja in dem Sinne unkompliziert, wollte nur eben mit dem umschreiben Zeit sparen.
Mit den direkten Namen kann ich auch was auslassen, was ja beim normalen Array eher nicht geht.
Die Idee dahinter ist, dass die ID mit dem Namen der Variable verknüpft ist.

Wie gesagt so wäre es suchen/ersetzen und wäre mal schnell umgeschrieben.
So muss ich das wieder auf 2 andere Arten schreiben.

Wie gesagt bei IntelliJ, wenn ich einen Algorithmus laufen lasse, wenn ich was ausprobiere habe das Ergebnis ob es geht in 3sek oder so. Wenn ich das selbe in Android mache, dann dauert das gefühlt ewig bis der Emulator startet.

Oder gibt es eine Möglichkeit eine Ausgabe in Android Studio ohne Ausgabe zu starten ?
 
Array ist ja in dem Sinne unkompliziert, wollte nur eben mit dem umschreiben Zeit sparen.
Mit den direkten Namen kann ich auch was auslassen, was ja beim normalen Array eher nicht geht.
Die Idee dahinter ist, dass die ID mit dem Namen der Variable verknüpft ist.

Wie gesagt so wäre es suchen/ersetzen und wäre mal schnell umgeschrieben.
So muss ich das wieder auf 2 andere Arten schreiben.

Wie gesagt bei IntelliJ, wenn ich einen Algorithmus laufen lasse, wenn ich was ausprobiere habe das Ergebnis ob es geht in 3sek oder so. Wenn ich das selbe in Android mache, dann dauert das gefühlt ewig bis der Emulator startet.

Oder gibt es eine Möglichkeit eine Ausgabe in Android Studio ohne Ausgabe zu starten ?
 
Ja, dass weiß ich.

Ich suchte halt einfach eine Möglichkeit um auf String Namen zuzugreifen, die sich dynamisch zusammen setzen können.
Eben wie bei Android, einen strings.xml dann mit R.string.var1 zugreifen, nur eben im puren Java.

Oder man nennt es eben im XML
<string name="Essen1">Gulasch</string>
<string name="Essen2">Pfannkuchen</string>

und dann wollte ich per
for(....){
Integer id = context.getResources().getIdentifier("Essen" + i, "string", context.getPackageName());
String name = context.getString(id);
}
zugreifen
dann wäre eben Essen1 = Ausgabe Gulasch
und Essen2 = Ausgabe Pfannkuchen
 
Ich suchte halt einfach eine Möglichkeit um auf String Namen zuzugreifen, die sich dynamisch zusammen setzen können.
Dann schau Dir bitte Map an!

Das ist ja genau das, was ich meinte, was da vermutlich auch intern in den Klassen benutzt wird bei Android,
Evtl. werden Dateien gelesen und dann als Map gespeichert.
==> Da hattest Du bereits den Hinweis auf Map.

Generell solltest Du Dir ansehen, was für Collections Java bietet, was diese auszeichnet und was für Implementationen es gibt. Speziell zu nennen sind List, Set und Map. Und dann konkrete Implementationen wie ArrayList, HashSet und HashMap (Gibt aber noch mehr).

Das ist aber dein kein dynamisches Zugreifen auf Variablen. Variablen sind nur im Programmablauf für den Programmierer da. Du willst aber mit Daten hantieren. Und da willst Du ja deutlich flexibler sein. Du hast var1, var2 und var3... Nun will ich als Anwender aber auch "var5" und "hallo" und "Dududu" haben ... Das sind ja Werte...
 
Nein so ist es auch nicht.
Wie gesagt in Android sind im best case die Strings ausgelagert, damit die übersetzt werden können. Zieht sich ja die App je nach Sprache selbst.
Siehe oben, die Variablen gibt es nicht. Es gibt in meinem Fall nur fest definierte Variablen wo es auch einen Text zu gibt. Sprich, gibt es die id nicht, gibt es auch den string nicht.
 
Kann ich das nachbilden
Genau das könntest du tun!

Java:
import java.util.HashMap;

public class MExample {
    private HashMap<String, String> map = new HashMap<>();

    public void addToMap(int i) {
        map.put("var" + i, "Text " + i);
    }

    public String getFromMap(int i) {
        return map.get("var" + i);
    }

    public void printAll(int limit) {
        for (int i = 0; i < limit; i++) {
            System.out.println(getFromMap(i));
        }
    }

    public static void main(String[] args) {
        MExample me = new MExample();
        me.addToMap(0);
        me.addToMap(1);
        me.addToMap(2);
        me.addToMap(3);
        me.printAll(4);
    }
}

Mit einer TreeMap wäre alles sogar noch sortiert.

Edit: Bitte aufpassen bei der printAll... denn sie setzt vorraus, dass bis limit alle Variablen eingefügt wurden.
 
Nur so am Rande: für so Listen-artige Dinge nutzt man bei Android auch Arrays, und nummeriert nicht die Strings durch: https://developer.android.com/guide/topics/resources/string-resource#StringArray

Anstatt die schlechte Lösung für Android in normales Java zu überführen, ist's vermutlich sinnvoll, die gute Lösung aus Android als Ausgangspunkt zu nutzen. Dann lässt sich der Code auch wirklich eins-zu-eins überführen (bis auf das initiale Füllen des Arrays, was man dann aber sinnvollerweise vom Rest trennt).
 
Zuletzt bearbeitet:
Wer redet hier eigentlich von Android?
Der TO:
In Android geht das ja mit der String.xml so
Siehe mein Android Beispiel, da liegen die Variablen auch nicht im Array, sondern in einer xml
In Android spricht man ja zur Not oder anders den String mit R.string.var1 an.
und wenn ich dann wieder in Android bin, sage ich einfach suchen/ersetzen string. -> R.string.
Eben wie bei Android, einen strings.xml dann mit R.string.var1
 
Ist soweit richtig, aber ich habe sozusagen mehrere Sparten und da kann ich nicht einfach ein Array nehmen.
Sagen wir so, ich habe z.b.
Essen1 = Zucker
Essen2 = Mehl
dann kommt eine Weile nichts
Essen50 = Schnitzel
Essen51 = Filet
dann kommt eine Weile nichts
Essen100...
usw.
Dann müsste ich ja alles was leer ist auch leer definieren und das wäre in der XML ein paar 100 Zeilen.
Daher ist ja jede id einfach einem Wort zugeordnet
Gibt es die ID nicht, gibt es auch das Wort nicht.
 
Es gibt ansonsten durchaus auch noch einige vergleichbare Möglichkeiten in Java, wenn man in einer Datei im Projekt Werte setzen möchte, um dann auf diese zuzugreifen.

Denkbar wäre z.B. eine einfache Properties Datei, welche dann mit Hilfe der Klasse Properties geladen würde. Dann könnte man z.B. Strings in der Form hinterlegen:

[CODE title="Strings.properties Datei"]Hello=Hello World!
bye=Und Tschüss[/CODE]

Code:
Properties strings = new Properties();
strings.load(getClass().getResourceAsStream("/strings.properties"));

[CODE lang="java" title="Laden einzelner Meldungen"]System.out.println(strings.getProperty("hello","Hallo!"));
System.out.println(strings.getProperty("bye","Bye Bye"));[/CODE]


Oder generell auch ResourceBundle: https://www.baeldung.com/java-resourcebundle

So eine Map müsste man also nicht zwingend irgendwie groß selbst erzeugen.

Aber ich hatte auch schon angedeutet: Wenn man sowas bräuchte, gibt es viele Möglichkeiten, incl. XML Serialisierung mittels z.B. Jackson.

Was dann aber ggf. fehlt ist die automatische Generierung von den Ids. Das ist evtl. ein Punkt, der noch fehlt, denn es ist schon hilfreich, wenn man gewisse Kontrollen hat, dass der Key auch wirklich existiert und bei Änderungen überall angepasst wird. Also ein Tippfehler würde oben nicht bemerkt ...
Oder gibt es eine Möglichkeit eine Ausgabe in Android Studio ohne Ausgabe zu starten ?
Bezüglich Android Studio und Testen: man kann einiges an Funktionalität ggf. auch per Unit Tests testen. Dann braucht es auch keinen Android Emulator. Siehe zu dem Thema ggf. https://developer.android.com/training/testing/unit-testing.
 
Ist soweit richtig, aber ich habe sozusagen mehrere Sparten und da kann ich nicht einfach ein Array nehmen.
Sagen wir so, ich habe z.b.
Essen1 = Zucker
Essen2 = Mehl
dann kommt eine Weile nichts
Essen50 = Schnitzel
Essen51 = Filet
dann kommt eine Weile nichts
Essen100...
usw.
Dann müsste ich ja alles was leer ist auch leer definieren und das wäre in der XML ein paar 100 Zeilen.
Daher ist ja jede id einfach einem Wort zugeordnet
Gibt es die ID nicht, gibt es auch das Wort nicht.
Das klingt sehr danach, dass sowohl Strings als auch Arrays das falsche dafür sind.

Die Zahlen sollen eine Kategorie oä darstellen, also 1-49 gehören irgendwie zusammen, 50-49 gehören zusammen, usw?
 
Was man sich natürlich auch überlegen kann, ist ein Code-Generator. Aus einer XML Datei wird dann per XSLT eine .class generiert - vor dem übersetzen des Java Codes. Das ist dann wohl auch in etwa das, was bei Android gemacht wird, denn aus diversen Quellen müssen ja die IDs und so extrahiert und zur Verfügung gestellt werden, damit dieses R.... zur Verfügung steht. Und das am Besten mit einem Plugin für die IDE, damit die IDE auch weiss, was generiert wird.

Ich würde mich auch nicht wundern, wenn es da etwas fertiges gäbe. Nur rein der Generator ist aber relativ einfach zu bauen, da ja nur relativ wenig Dinge gewusst werden müssen.

Es wäre also Denkbar, ein XML wie folgt aufzubauen:
XML:
<generator class="Constants" package="test">
        <import>java.util.List</import>
        <constant type="String" name="test" value="test-value"/>
        <enum name="strings">
            <element name="test" value="test-value"/>
        </enum>
</generator>

Und über ein XSLT würde dann bei dem Beispiel generiert:
Java:
package test;

import java.util.List;

public class Constants {

    public static String test = "test-value";

    public enum strings {
        test("test-value");

        private String value;
        strings(final String value) { this.value = value; }
        public String toString() { return value; }
    }
}

Das XSLT sollte nicht schwer zu erstellen sein. Aufruf in einem Build Tool sollte auch unproblematisch sein, z.B. in Maven mittels exec-maven-plugin.

Das wäre dann halt etwas, das einem hilft, später auch eine Kontrolle zu haben. Wenn man also etwas nutzt wir Constants.gibtEsNicht, dann bekommt man eine Compile-Warnung. Und es gibt Type-Checks und so ...

Aber ich bin mir sicher, dass es auch etwas Fertiges gibt. Also entweder das, was da für Android verwendet wird einfach übernommen für andere Projekte oder eben fertige Code Generatoren, die sowas bieten. Ich hatte da bisher halt nur keinen Bedarf für sowas, daher kenne ich da jetzt nichts. Und bei meinen Suchen habe ich da irgendwie nichts wirklich passendes gefunden.
 
Danke für die Mithilfe. Habe es noch nicht ausprobiert, aber scheint so als wenn in meinem Fall Properties in Kombination mit einem XML file das richtig ist. Gut die Abfrage müsste ich 2 verschiedene Befehle nicht, ist ja nicht so das Ding und anstatt.
<string name="lebensmittel1">Gulasch</string>
würde ich dann einfach
<entry key="lebensmittel1">Gulasch</entry>
schreiben und die Worte sind schnell mit suchen und ersetzen erledigt.

Was ich aber nicht hin bekommen habe direkt in Android Studio auf der Konsole testen.
Ich bekomme irgendwie die String.xml nicht angesprochen. Der bringt keinen Fehler,
aber wenn ich eben System.out.println(R.string.lebensmittel1);
nehme, dann schreibt der eben nicht Gulasch, sondern null
 

Zurück
Oben