Kann ich eine Methode schreiben die alle Arten von funktionalen Interfaces akzeptiert..?

sirbender

Top Contributor
Hallo,

ich wuerde gerne eine Methode schreiben die als Parameter jedes "FunctionalInterface" Objekt akzeptiert.

Runnable r;
methode(r)

Supplier<String> s;
methode(s)

usw.

Geht sowas mit irgendwelchen Tricks?
 
Was willst du denn erreichen?
Ein Runnable hat ja nicht wirklich irgendetwas mit einer BiFunction zu tun...


Du kannst natürlich Objekt als Parametertyp nehmen, mehr haben beliebige Interfaces nicht gemeinsam
 
Natürlich,
Java:
	public static void m(Object o) {

	}

	public static void main(String[] args) {
		Runnable r = null;
		Supplier<String> s = null;
		m(r);
		m(s);
	}


Der Sinn sei mal dahingestellt.
Es gibt allerdings keinerlei Möglichkeit herauszufinden ob o ein Funktionales Interface is.
 
Java:
public static boolean test(Class<?> clazz) {
    if (!clazz.isInterface()) {
        return false;
    }
    return Arrays.stream(clazz.getMethods())
            .filter(not(Method::isDefault))
            .filter(not(method -> Modifier.isStatic(method.getModifiers())))
            .count() == 1;
}

public static void main(String[] args) {
    System.out.println("Function: "+test(Function.class));
    System.out.println("Runnable: "+test(Runnable.class));
    System.out.println("List: "+test(List.class));
}

Code:
Function: true
Runnable: true
List: false
 
Zuletzt bearbeitet:
Ich weiß gar nicht warum ich noch antworte...
Java:
	private static class Toll {
		public static void toll() {

		}
	}

	public static boolean m(Object o) {
		return Arrays.stream(o.getClass().getDeclaredMethods()).filter(Predicate.not(Method::isDefault))
				.filter(Predicate.not(method -> Modifier.isStatic(method.getModifiers()))).count() == 1;
	}

	public static void main(String[] args) {
		Runnable r = new Runnable() {
			@Override
			public void run() {
			}
		};
		Supplier<String> s = new Supplier<String>() {
			@Override
			public String get() {
				return null;
			}
		};
		System.out.println(m(r));
		System.out.println(m(s));
	}
 
Ich weiß es auch nicht, ich weiß allerdings auch nicht, was dein Code zeigen soll? Das konkrete Implementierungen mehr als nur eine öffentliche Methode haben? Das hätte ich dir auch so sagen können...
 
Ein einfaches Nein auf eine Frage eines TE ist für dich nicht akzeptierbar oder?

Natürlich ist nicht nach einer Methode gefragt die ein Class<?> bekommt.
 
Deshalb steht dort, was man machen muss, um zu testen, ob ein Objekt ein Funktional Interface "ist": "Man kann prüfen, on ein Super-Interface mit @FunctionalInterface annotiert und ein "SAM-type" ist" 🙂


Aber wenn es jetzt schon darum geht, nach was der TO konkret gefragt hast: Deine Antworten beziehen sich genauswendig darauf (TO fragt nach "jedes 'FunctionalInterface' Objekt", du liefest Code der nur zwei konkrete behandeln kann) und sind zT noch falsch ("Es gibt allerdings keinerlei Möglichkeit herauszufinden ob o ein Funktionales Interface is.").
Grade du solltest dich mal zurückhalten.
 
Dann schreibe doch eine Methode, die prüft, ob o ein funktionales Interface ist...

Wenn das nicht möglich ist, ist meine Antwort auch nicht falsch.

So das soll dann auch mein letzter Beitrag gewesen sein.
 
Dann schreibe doch eine Methode, die prüft, ob o ein funktionales Interface ist...

Wenn das nicht möglich ist, ist meine Antwort auch nicht falsch.
Ich dachte du bist so gut, und dann bekommst du das nicht selber hin? 😉

Hier, Bitteschön.

Ob das allerdings sinnvoll ist? ArrayList ist halt genauso Implementierung eines Funktional-Interfaces wie (int i) -> i > 42...

Java:
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.*;

import static java.util.function.Predicate.*;


public class SamTest implements Predicate<Object> {

    public boolean test(Object o) {
        return getParentClasses(o.getClass()).stream().anyMatch(c -> test(c));
    }

    private static Set<Class<?>> getParentClasses(Class<?> clazz) {
        Set<Class<?>> classes = new HashSet<>();

        Queue<Class<?>> toDo = new ArrayDeque<>();
        toDo.add(clazz);
        do {
            Class<?> next = toDo.remove();
            if (classes.contains(next)) {
                continue;
            }
            classes.add(next);
            Collections.addAll(toDo, next.getInterfaces());
            if (next.getSuperclass() != null) { toDo.add(next.getSuperclass()); }
        } while (!toDo.isEmpty());
        return classes;
    }

    public static boolean test(Class<?> clazz) {
        if (!clazz.isInterface()) {
            return false;
        }
        return Arrays.stream(clazz.getMethods())
                       .filter(not(Method::isDefault))
                       .filter(not(method -> Modifier.isStatic(method.getModifiers())))
                       .count() == 1;
    }

    public static void main(String[] args) {
        Predicate<Object> samTest = new SamTest();

        Runnable r = new Runnable() {
            @Override
            public void run() {
            }
        };

        System.out.println("new Runnable(): " + samTest.test(r));
        System.out.println("new ArrayList(): " + samTest.test(new ArrayList<>()));
        System.out.println("new Object(): " + samTest.test(new Object()));

    }

}
 
Puhh...ich wollte hier keinen Streit vom Zaun brechen 🙁

Ist nicht jedes @java.lang.FunctionalInterface() ein SAM aber nicht jedes SAM ein @java.lang.FunctionalInterface() ?

Ich glaube du testest nur auf SAM, oder?

Apropos, wenn ich "Object o" als Parameter nehme gehen der direkte Aufruf ueber Method-Referenzen nicht mehr.

// geht nicht
main.method(main::someMethod)
// geht
Runnable r = main::someMethod;
main.method(r);

Kommt mir irgendwie komisch vor, dass die Methoden-Referenz main::someMethod nur "Sinn" macht wenn eine main.method(Runnable r) existiert. Ein main.method(Object o) fuehrt zum Compilerfehler. Irgendwie sind Method-References weird.

Java:
        Supplier<String> sup = () -> "greeting from supplier";
               
        Class<?>[] interfaces = sup.getClass().getInterfaces();
        for (Class<?> intrface : interfaces) {
            System.out.println(intrface);
            Annotation[] annotations = intrface.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println("\t" + annotation);
            }
        }
 
Zuletzt bearbeitet:
Ist nicht jedes @java.lang.FunctionalInterface() ein SAM aber nicht jedes SAM ein @java.lang.FunctionalInterface() ?
Nein, mit @FunctionalInterface kann man entsprechende Interfaces anmontieren (und auch nur solche), es ist aber kein Muss. Closeable zB ist ein SAM-Type ohne Annotation.
Apropos, wenn ich "Object o" als Parameter nehme gehen der direkte Aufruf ueber Method-Referenzen nicht mehr.

// geht nicht
main.method(main::someMethod)
// geht
Runnable r = main::someMethod;
main.method(r);

Kommt mir irgendwie komisch vor, dass die Methoden-Referenz main::someMethod nur "Sinn" macht wenn eine main.method(Runnable r) existiert. Ein main.method(Object o) fuehrt zum Compilerfehler. Irgendwie sind Method-References weird.
Dürfte an den Grenzen der Typeinference liegen, es ist halt nicht klar, was für ein Typ das sein soll - kann hab Runnable oder Closeable sein.


Java:
        Supplier<String> sup = () -> "greeting from supplier";
              
        Class<?>[] interfaces = sup.getClass().getInterfaces();
        for (Class<?> intrface : interfaces) {
            System.out.println(intrface);
            Annotation[] annotations = intrface.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println("\t" + annotation);
            }
        }
Ja, so könnte man auf die Annotation prüfen (wobei du alle interfaces rekursiv durchlaufen müsstest).
Aber damit gäbe es noch Fälle, in denen du Lambdas übergeben kannst, deren Interfaces keine Annotation haben.
 

Zurück
Oben