Tony
Tony

Reputation: 1155

Calling a function without doing a new

I wrote a sort function and class in Java:

public class MiscellaneousUtilities {

    /**
     * Changes a list of "First Last" to "Last, First" and "First Middle Last" to "Last, First Middle", etc.
     */
    public static Function<String, String> ToLastFirstFunction = new Function<String, String>() {
        @Override
        public String apply(String nm) {
            String[] nmarr = nm.split(" ");
            int last = nmarr.length - 1;
            String res = nmarr[last];
            if (last > 0) {
                res += ",";
            }

            for (int i = 0; i < last; i++) {
                res += " " + nmarr[i];
            }

            return res;
        };
    };
}

When I want to use it I can't just say MiscellaneousFunctions.ToFirstLastFunction()

I have to do a new MiscellaneousFunctions().ToFirstLastFunction;

I tried putting static in front of the class declaration but it allows only public, final and abstract. Looking at the Math class if I want to use Math.min() I don't have to do a new Math().min(). Math is also defined as a class that does not have static in front of it, and min() does as does ToFirstLastFunction, so I don't understand the difference.

Upvotes: 2

Views: 675

Answers (3)

slim
slim

Reputation: 41223

Math.min() is a a method not a function, declared like this in Math.class:

public int min(int a, int b) {
    ...
}

... and it is methods like this that you can invoke directly as in int x = Math.min(3,2).

You have created a public static class variable called ToLastFirstFunction -- that's not something you can call like a method. But you can do things with it using the methods in the java.util.function.Function interface -- the simplest being apply():

String out = MiscellaneousFunctions.toFirstLastFunction.apply("John Doe");

(I changed the capitalisation of your identifier -- find out about Java capitalisation conventions)


It is not the case that you can call your public static Function<...> using new MiscellaneousFunctions().toFirstLastFunction("John Doe") -- I'm not sure why you thought it was so.

You can do new MiscellanousFunctions().toFirstLastFunction.apply("John Doe") -- but your compiler should warn you about accessing a static variable via an instance. MiscellanousFunctions.toFirstLastFunction.apply() is the right way.


So the short answer to your question is: if you want to invoke it that way, write it as a method.


But if that's the case, why would you define an operation as a function, rather than a method?

Well, functions have the benefit that, unlike methods(*), they are objects -- so you can pass them around, put them in collections, assign them to variables. And they have methods like compose() and andThen() which return a new function that combines this function with another.

So you can do things like:

Map<String,Function<String,String> nameTranslationStrategies = new HashMap<>();
nameTranslationStrategies.put(
   "no change", x -> x);
nameTranslationStrategies.put(
   "to first-last", 
   MiscellaneousFunctions.toFirstLastFunction);
nameTranslationStrategies.put(
   "capitalised first-last",
   MiscellaneousFunctions.toFirstLastFunction
        .andThen( s -> s.toUpperCase());

...

String nameTranslationOption = config.getProperty("nameTranslationOption");
String name = nameTranslationStrategies
     .get(nameTranslationOption)
     .apply(inputString);

Java programmers managed for decades without this feature -- functions didn't exist until Java 8. But you can do lots of neat things with them.

Even so, this isn't a reason to write your code as a Function bound to a static variable, since you can access ordinary methods as functions using the :: syntax:

  Function<Double,Double> logarithm = Math::log;
  double x = logarithm.apply(2.0);

Note also, that you've used a long-winded syntax to define your function:

 public static Function<String, String> slimify = new Function<String, String>() {
    @Override
    public String apply(String s) {
         return "slim says " + s;
    }
 }

... can be written as:

public static Function<String,String> slimify = s -> {
    return "slim says " + s;
}

... or even (since this one's a one-liner)

public static Function<String,String> slimify = s -> "slim says " + s;

It's good to know the long-winded way, because it shows how functions work behind the scenes. But in real world code, the shorter form is the way to go, as it is more expressive: the intent of the code isn't hidden by clutter. This is such a quick and easy way of expressing a function, that people often use them in-line rather than assign them to a variable -- as I have done in the map example above.


(*) I said that methods are not objects. This isn't strictly true -- partly because you can get one as an object using ::, but also because you can use Java's Reflection API to access classes and methods as objects. But you don't want to use Reflection, unless you really know you need to.

Upvotes: 1

Shadov
Shadov

Reputation: 5592

Math.min() is a public static method called min, your Function is a Function object, it's not a method. Your object has a method apply and you have to use that method for what you want to achieve, like this:

MiscellaneousFunctions.ToFirstLastFunction.apply(something)

Upvotes: 0

Adam Arold
Adam Arold

Reputation: 30528

That's because you have to call that function with an apply like this:

MiscellaneousFunctions.ToFirstLastFunction.apply("yourstring");

You can add an other static function as a shorthand though:

public static String toFirstLast(String str) {
    return ToLastFirstFunction.apply(str);
}

The main difference between Math.min and your solution that Math.min is a regular static method while you have a Function object and those can be called with apply.

Upvotes: 2

Related Questions