24

The Function Interface is introduced in Java 8, to implement functional programming in Java. It represents a function that takes in one argument and produces a result. It's easy to practise and read, but I am still trying to understand the benefit of it other than just making it look cool. For example,

Function<Integer, Double> half = a -> a / 2.0;
Function<Double, Double> triple = b -> b * 3;
double result = half.andThen(triple).apply(8);

can just be converted as a standard method like

private Double half(int a) {
    return a / 2.0;
}
private Double triple (int b) {
    return b * 3;
}
double result = triple(half(8));

So what's the benefit of using Function? As it refers to functional programming, what exactly is functional programming in Java and benefit it could bring? Would it benefit the way like:

  1. execution of chaining functions together (e.g andThen & compose)
  2. usage inside Java Stream?
  3. the access modifier as function tends to define with private not public, while method can be either?

Basically, I'm curious to know, in what circumstances would we prefer using function rather than normal method? Is there any use case that's unable or difficult to use, or converted with a normal method?

5
  • 9
    passing callbacks for example Commented Aug 11, 2021 at 3:37
  • yeah that could be one usage, but that could also be converted like the old way. Especially the callback would be handled in different situations from the caller. But sometimes I have to go back and forth to understand the code when using it as a callback. Commented Aug 11, 2021 at 3:40
  • In this answer I needed a function to pass to a Comparator that would depend on additional input (so sort order would depend dynamically). Using a static method declaration would have required adding a field for the additional input, which would be ugly. Defining a Function dynamically solved it. Commented Aug 11, 2021 at 4:49
  • The only reason is when you want to treat a function as an object. There is no reason to use a function for something as trivial as your examples. Commented Aug 12, 2021 at 9:33
  • And in the reality, in java, these maldas assigned to functional interfaces are implemented as objects via anonymous classes. At least it worked this way few versions ago ;-) Commented Aug 16, 2021 at 19:39

8 Answers 8

20

One usage of Function is in Streams. Everyone uses map method these days, I believe:

This map method accepts the Function as a parameter. This allows writing a pretty elegant code - something that could not be achieved before Java 8:

Stream.of("a", "b", "c")
   .map(s -> s.toUpperCase())
   .collect(Collectors.toList());
// List of A, B, C

Now its true that there are method references and functional interfaces (one of which is Function of course), this lets you using method reference to rewrite the above example as:

Stream.of("a", "b", "c")
    .map(String::toUpperCase)
    .collect(Collectors.toList())

... but that's only a syntactic sugar - map still accepts the Function as a parameter of course.

Another example that uses Function from Java itself is StackWalker: Here is an example:

List<StackFrame> frames = StackWalker.getInstance().walk(s ->
    s.dropWhile(f -> f.getClassName().startsWith("com.foo."))
     .limit(10)
     .collect(Collectors.toList()));
}

Note the call to walk method - it accepts a function as a parameter.

So bottom line, it's just yet another tool that can help the programmer to express his/her intentions. Use it wisely wherever appropriate.

Sign up to request clarification or add additional context in comments.

Comments

13

Suppose I want to write an applyTwice function:

double applyTwice(double x, Function<Double, Double> f) {
  return f.apply(f.apply(x));
}

This needs the function be represented as an object.

Functions are useful when you want to put some structure around arbitrary code supplied by the caller.

3 Comments

Yeah this could be one, pretty similar like Func<T,TResult> Delegate in C#.
To me, this is the main reason for creating and using Functions. Then they can be passed as arguments, like variables.
Seems to be similar to JS closures ;-)
4

In Java it's usually called "pure functions", which are defined alike:

  • The execution of the function has no side effects.

  • The return value of the function depends only on the input parameters passed to the function.

Anything else should be an object's method.

4 Comments

Thank you! I am trying to understand a "non-pure function" from No.2, a "non-pure" function may refer to a function that it's executing with some external class that is not passed in as its input param, for example, those external class may be initiated outside the function, would that sound correct? For No.1, what does the "side effect" refers here? Is there any tiny example?
@KevD. An undesired "side effect" could be, that a property of an object is being mutated - and a method doesn't necessarily require any input parameters, because it can refer to instance or static methods & properties within it's scope of execution... while a pure function is 100% standalone, depends on nothing else and mutates nothing else, but only has input parameters and a return value (these barely return void, because it would be pointless).
Side effects should be avoided, regardless, don't you think? Not just for Function.
@PhilFreihofner When a method mutates an object, this is usually not being considered as a "side effect", but it may be the actual intent, of what the method is supposed to do.
4

One example I had to use just a few days ago at my workplace is when I wanted to lazily compute a message, depending on a condition. For example imagine a logger usage like this:

  logger.debug("my-heavy-computed-message-here");

Now imagine that the computation of "my-heavy-computed-message-here" is really just that - it is heavy to compute; but you only want to present it if the DEBUG logger is enabled. What people usually do is:

if(logger.isDebugEnabled()) {
    logger.debug("my-heavy-computed-message-here");
}

This is ugly. Instead, we have some code in place that takes a Function (or Supplier) as input:

 logger.debug(Function<SomeObject, String> function)

Internally in our logger implementation we call function::apply (thus computing that expensive String) only as needed (or in a 'lazy' fashion).

4 Comments

Hey that's an interesting example, I am curious about the function you defined to replace the if(logger.isDebugEnabled(), how could we do that and are we passing logger as input parameter to the function?
@KevD. No no, we do not replace it. We just move it internally to the lib codebase, so that you do not have to do it yourself.
This example lacks the actual Function (which may or may not be a pure function).
@MartinZeitler and where exaclty in the OP question have you seen mentioning about pure? And the Function is whatever you choose to do, as long as your output of that is a String. Your comment makes no sense. And side effects are usually an invariant of a java function anyway, at least this is documented.
1

Instead of inheritance with overrides, i.e. anonymous instances, pass function-ality.

Say you create a class, but one bit of calculation must be provided.

class C {
    protected abstract int f(int x);
}

class Child1of99 extends C {
    @Override
    protected int f(int x) { return x / 42; }
}

or

new C() {
    @Override
    protected int f(int x) { return x / 42; }
}

Alternatively you can do:

class C {
    private final IntOperation f;

    C(IntOperation f) {
        this.f = f;
    }
}

 new C(x -> x / 42);

Comments

1

As far as functional interfaces are concerned, I believe it makes "behaviours" more agile, what I mean by that is with the help of functional interface you can easily and quickly provide behaviour to other members and that's not the case with conventional methods. So, basically with instance methods your behaviour stick to the objects, alternatively static methods can provide a better scope and may be accessible across all classes but again it's not dynamic at all.

Consider following example,

class Math {

    int sum(int a, int b) {
        return a + b;
    }
}

Now my sum method is fix and can not be changed, now consider the following example with functional interfaces,

interface Sum {
    int sum(int a, int b);
}

Now I can have different behaviours,

Sum nocheckSum = (a, b) -> a + b;
Sum positiveNumSum = (a, b) -> {
                                    if(a < 0 || b < 0) throw new IllegalArgumentException("Only positive numbers are allowed!");
                                    return a + b;
                               };

May be this is not the best example but I guess you got my point.

Now the benefit of this mechanism is that you don't need to declare and manage methods for different behaviours, you can dynamically create one and use it for specific purposes. At the same it's also important to mention that if you are sure that the behaviour has to be common for all who consume it, then I would not recommend to enforce functional interfaces but if it can and may change for not all but specific group of method consumers then definitely functional interfaces can be helpful.

Bottom line is, both either method or functional interfaces have their own significance in the language, even if we can use them interchangeably more better option would be to consciously choose one of them based on your business requirements.

Comments

0

In general, functional programming (lambdas, functional interfaces) serves the best operations like transformations and processing. In contrast, OOP programming (using methods) works the best when you have to store data (f.ex in memory), mutate it from time to time, or send a message between components. As usual, it depends. To all generalizations, you have exceptions.

Comments

-1

Basically, Java function are built in, error free, optimized, powerful functions that fit your requirements. Developers used best algorithms in Java functions to reduce the time and space complexity.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.