-2

what type to use, when i wish to pass a lambda to a function, with lambda accepting and returning an object?

Example of the use can be seen below. I wanna be able to create instances of Foo, where each instance can is able to, in this example, call a prespeficied getter function.

class Foo() {
public ? lambdaFunction;

public Object doSomething(Object arbitraryClass);
    return lambdaFunction(arbitraryClass);
}

foo.lambdaFunction = (Object object) -> ((SomeClass) object).getAttribite())
foo.doSomething(someClassInstance);

I have a large number of classes with number of getable attributes, and need to be able to get all of those attributes at different places, but the only thing that changes is the actually classes getter name.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
Zerg Overmind
  • 955
  • 2
  • 14
  • 28

3 Answers3

2
class Foo {
    private final Function<Object, ?> func;

    public Foo(Function<Object, ?> func) {
        this.func = func;
    }

    public Object doSomething(Object in) {
        return func.apply(in);
    }
}

But I doubt you actually want that. Java is a nominally typed language - you're supposed to use names, and lots of them. 'Object' doesn't mean much. For example, given that the function needs to be able to convert any object, the function you pass in can't do anything with that object (well, other than toString, hashCode, and the other methods all objects have). The function could cast the input, but that's ugly.

This sounds like a better plan already:

class Foo<F, T> {
    private final Function<? super F, ? extends T> func;

    public Foo(Function<? super F, ? extends T> func) {
        this.func = func;
    }

    public T doSomething(F in) {
        return func.apply(in);
    }
}

F and T are short for 'from' and 'to'. The reason it's ? super F is because if you are looking to convert, say, strings to integers, and you have a function that convert any object to an integer, that's good too: You want it to convert either String, or any supertype thereof, and for the 'to', any subtype is also fine.


Extending this answer in light of your recent comments:

Java isn't dynamically typing. No random mysterymeat grabbags of functions that may or may not even make sense given the provided input. Thus, if you want a 'function that describes a setter, e.g. that takes 2 input arguments', then that's a completely different concept: That'd be a function that requires a Receiver and a new Value to set, and returns nothing. 2 inputs, 0 outputs. j.u.f.Function is 1 input, 1 output.

2 inputs, 0 outputs would be java.util.function.BiConsumer<T, U>. Look at the java.util.function API for these types.

class Example {
    private String name;

    public void setName(String name) { this.name = name; }
    public String getName() { return name; }

    public static final BiConsumer<Example, String> SETTER = Example::setName;
}

class SomeplaceElse {
    void foo() {
        Example e = new Example();
        String n = "hello";
        Example.SETTER.accept(e, n);
        System.out.println(e.getName()); // prints 'hello'
    }
}
rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • Can the input and output type be specified somehow by passing the class as another parameter to constructor? Uses of this class actually know what types are being used. Its just the `Foo` has to be able to cover all of them. But the class of the output can be passed to constructor (is known at the time). – Zerg Overmind Nov 11 '20 at 16:23
1

java.util.function.Function is the type to use.

nkrivenko
  • 1,231
  • 3
  • 14
  • 23
  • java.util.function.Function – fps Nov 11 '20 at 16:15
  • If i mind an additional question, how do you extend this to setter, aka, accepting 2 object arguments (the first one being the class, second one being the attribute value)? – Zerg Overmind Nov 11 '20 at 16:17
1

java.util.function.Function<T,R>, where T is the type of its argument and R is its return type.

But if you really plan having a public Function<Object,Object> lambdaFunction; field, that may not be the best design ever, you should use your actual types, not casting things back and forth.


For the extension appearing in a comment: look into the containing package, https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/function/package-summary.html to see what else is "ready".
For having 2 arguments and returning something, you can use BiFunction<T,​U,​R>. For having 2 arguments and returning nothing, you can use BiConsumer<T,​U>. And if you don't find what you need, then you can create your own interface and tag it as @FunctionalInterface. But that leads to a duplicate question, What are functional interfaces used for in Java 8?

tevemadar
  • 12,389
  • 3
  • 21
  • 49