Datentypen Methode aus einer Liste callen

Ich habe eine Methode die mir folgende Formate zurück gibt [LinkedList<Map<Object, List<String>>>].

In der List<String> sind die Methoden des Objektes drin die ich ausführen soll. Habt ihr eine Idee wie ich da ran komme? bzw Was ich mir zu dem Thema angucken könnte?

Was ich bisher versucht habe:
- Das ganze erstmal in eine LinkedList Variable ausgeben
- Danach foreach Entry(Objekt) der LinkedList in Map convertiert.
- und probiert dann Key und Value rauszuholen aber das hat nicht funktioniert.
 
K

kneitzel

Gast
Also erst einmal finde ich es immer relativ erschreckend, wenn ich solche Konstrukte sehe. Da würde ich immer etwas darüber nachdenken, dies zumindest zum Teil kapseln, damit man dann eine List<Irgendwas> hast und das Irgendwas hat dann halt innen drin eine Map<Object, WasAnderes> oder so. Das macht es dann deutlich leichter verständlich und Du hast es stärker gekapselt was Änderungen vereinfacht, so dies notwendig wird.

Aber davon mal abgesehen: Du hast die Namen von Methoden, die Du aufrufen musst. Eine Möglichkeit, die natürlich gehen kann, ist Reflection. Da holst Du Dir unter dem Strich vom Objekt die Klasse (getClass()), da kannst Du Dir dann die Methode heraussuchen (getMethod(name, <Parameter Typen>)) um dann invoke auf der Method Instanz aufzurufen.

Reflection ist aber relativ langsam und das ist ein Design das man teilweise gerne vermeiden möchte. Da ist es aber schwer, etwas vorzuschlagen ohne dass man den ganzen Ablauf kennt.

Eine Möglichkeit könnte z.B. ein (oder ggf. mehrere) funktionales Interface sein, das die Signatur der Methode enthält, die aufgerufen werden soll. Dann wäre die Map halt ein Map<Object, DeinFunktionalInterface> und bei dem Füllen würde man Methoden-Referenzen oder lambda Ausdrücke angeben (die dann aufgerufen werden können).

Oder wenn es immer die gleichen Aufrufe sind, die bekannt sind, dann wäre da auch eine Enumeration denkbar. Und den Elementen der Enumeration würde man dann das Wissen über den genauen Aufruf mitgeben. (Also streng genommen nur eine Variation der ersten Alternative.)

Das einfach nur um mal Möglichkeiten zu skizzieren.
 
Also erst einmal finde ich es immer relativ erschreckend, wenn ich solche Konstrukte sehe. Da würde ich immer etwas darüber nachdenken, dies zumindest zum Teil kapseln, damit man dann eine List<Irgendwas> hast und das Irgendwas hat dann halt innen drin eine Map<Object, WasAnderes> oder so. Das macht es dann deutlich leichter verständlich und Du hast es stärker gekapselt was Änderungen vereinfacht, so dies notwendig wird.

Aber davon mal abgesehen: Du hast die Namen von Methoden, die Du aufrufen musst. Eine Möglichkeit, die natürlich gehen kann, ist Reflection. Da holst Du Dir unter dem Strich vom Objekt die Klasse (getClass()), da kannst Du Dir dann die Methode heraussuchen (getMethod(name, <Parameter Typen>)) um dann invoke auf der Method Instanz aufzurufen.

Reflection ist aber relativ langsam und das ist ein Design das man teilweise gerne vermeiden möchte. Da ist es aber schwer, etwas vorzuschlagen ohne dass man den ganzen Ablauf kennt.

Eine Möglichkeit könnte z.B. ein (oder ggf. mehrere) funktionales Interface sein, das die Signatur der Methode enthält, die aufgerufen werden soll. Dann wäre die Map halt ein Map<Object, DeinFunktionalInterface> und bei dem Füllen würde man Methoden-Referenzen oder lambda Ausdrücke angeben (die dann aufgerufen werden können).

Oder wenn es immer die gleichen Aufrufe sind, die bekannt sind, dann wäre da auch eine Enumeration denkbar. Und den Elementen der Enumeration würde man dann das Wissen über den genauen Aufruf mitgeben. (Also streng genommen nur eine Variation der ersten Alternative.)

Das einfach nur um mal Möglichkeiten zu skizzieren.

Ich finde diese Kapselung auch schrecklich. Besonders da es mir irgendwie unmöglich scheint sie sauber wieder zu entkapseln.

Vorgegeben ist ein Projekt mit verschiedenen packages und aus einer gegebenen Methode ( service.getTasks() ) bekomme ich dieses gekapselte Konstrukt heraus. Und soll jetzt die darin liegenden Methoden der darin liegenden Objekte ausführen.
Bloß leider scheitert es schon beim entkapseln.

Reflection war auch ein Ansatz den ich mir angeschaut hatte, da ich es aber nicht hin bekommen habe den key und die value der map zu separieren kam ich hier nicht weiter.

Die Idee mit dem funktionalen Interface klingt interessant und nach der besseren Lösung das werde ich mir auf jeden Fall mal durchlesen und versuchen.

Ich danke schon mal für die schnelle ausführliche Antwort und werde mich mal weiter daran versuchen.
 
K

kneitzel

Gast
Die Map kannst Du ja über diverse Wege ansprechen. Wenn Du über alle Elemente gehen willst, dann wäre z.B. Map.entrySet interessant. Darüber kannst Du dann iterieren und hast so Map.MapEntry Elemente (mit getKey() / getValue() Methoden).

Oder direkt das forEach, dass einen BiConsumer nimmt, welcher dann mit Key, Value aufgerufen wird.
 
Die Map kannst Du ja über diverse Wege ansprechen. Wenn Du über alle Elemente gehen willst, dann wäre z.B. Map.entrySet interessant. Darüber kannst Du dann iterieren und hast so Map.MapEntry Elemente (mit getKey() / getValue() Methoden).

Oder direkt das forEach, dass einen BiConsumer nimmt, welcher dann mit Key, Value aufgerufen wird.
Danke das hat mir super geholfen.

Ich poste mal hier meinen Code falls jemand dasselbe Problem hat. Kann das vielleicht helfen:

[CODE lang="java" title="Code"]
public static void executeOnLocationTasks(Service service) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

LinkedList tasks = service.getTasks();
Map map = (Map)tasks.get(0);
Iterator it = map.entrySet().iterator();

while (it.hasNext()) {

Map.Entry<Object,List<String>> entry = (Map.Entry)it.next();
Object obj = entry.getKey();
List<String> list = entry.getValue();

for(int i=0; i<list.size(); i++)
{
obj.getClass().getDeclaredMethod(list.get(i)).invoke(obj);
}
}

}[/CODE]
 

mrBrown

Super-Moderator
Mitarbeiter
Danke das hat mir super geholfen.

Ich poste mal hier meinen Code falls jemand dasselbe Problem hat. Kann das vielleicht helfen:

[CODE lang="java" title="Code"]
public static void executeOnLocationTasks(Service service) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

LinkedList tasks = service.getTasks();
Map map = (Map)tasks.get(0);
Iterator it = map.entrySet().iterator();

while (it.hasNext()) {

Map.Entry<Object,List<String>> entry = (Map.Entry)it.next();
Object obj = entry.getKey();
List<String> list = entry.getValue();

for(int i=0; i<list.size(); i++)
{
obj.getClass().getDeclaredMethod(list.get(i)).invoke(obj);
}
}

}[/CODE]
Der Code lässt sic aber deutlich schöner schreiben ;)

[CODE lang="java" title="Code"]
public static void executeOnLocationTasks(Service service) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<Map<Object, List<String>> tasks = service.getTasks();
var map = tasks.get(0);

for (var entry : map.entrySet()) {
Object obj = entry.getKey();
List<String> list = entry.getValue();

for(var methodName : list) {
// getMethod ist vermutlich passender als getDeclaredMethod. in beiden Fällen muss man sich aber der Fallstricke bewusst sein
obj.getClass().getMethod(methodName).invoke(obj);
}
}
}[/CODE]


Deine Lösung hat so ziemlich alles mitgenommen, was man da "unschön" lösen kann :/ (raw-types, unchecked cast, iterator, for-i, getMethod/getDeclaredMethod)
 

Neue Themen


Oben