2

In Java, I want to define a normalizing function that takes one number as input but whose behavior is defined by multiple parameters.

Essentially, the Java equivalent of this in Lisp:

(define (normalizeVal min max floor ceiling)
  (lambda (x) (/ (* (- ceiling floor) (- x min)) (+ (- max min) floor))))

In pseudo-code, I'd like to:

function parsing(data, normalizeValFunc) {
   for (datum in data):
      normalizeValFunc(datum);
}

var input = userData;
var min, max, floor, ceiling = /* Calculate min, max, floor, and ceiling */
var output = parsing(input, normalizeValFunc(min, max, floor, ceiling));

Passing functions as parameters in Java can be tricky because functions are not first class objects in Java. (Maybe Java 8 Lambda expressions changes this?) Other questions address the issue of passing functions as parameters in Java, such as How to pass a function as a parameter in Java?, What's the nearest substitute for a function pointer in Java?, and Function Pointers in Java

However, none of these questions concern passing a function whose behavior is defined by parameters other than the function's input value. I don't know in advance what the min, max, floor, and ceiling parameters of the normalization function will be, but I only want the effective normalizing function to take one argument, the value to be normalized.

Community
  • 1
  • 1
Scott Emmons
  • 1,831
  • 3
  • 13
  • 9
  • 1
    take a look at Guava Functions https://code.google.com/p/guava-libraries/wiki/FunctionalExplained – keuleJ Jun 10 '14 at 19:14
  • Nice reference. Would upvote you if I had enough reputation. – Scott Emmons Jun 10 '14 at 22:53
  • 1
    You need closures. Lambdas make it easy, but unfortunately anonymous class route is the only way in pre-Java 8. See [this](http://stackoverflow.com/questions/5443510/closure-in-java-7), [this](http://stackoverflow.com/questions/233579/closures-in-java-7) etc – nawfal Jul 05 '14 at 12:37

1 Answers1

5

The old-fashioned way of doing this is with an interface:

public interface Normalizer {
    int normalize(int value);
}

You would then create an instance of a Normalizer, e.g. with an anonymous class:

public static Normalizer normalizeValFunc(final int min, final int max, final int floor, final int ceiling) {
    return new Normalizer() {
        @Override public int normalize(int value) {
            /* Use min, max, floor, ceiling & value here to return something. */
        }
    };
}

Then you can write a function that takes a Normalizer:

void parsing(int[] data, Normalizer normalizer) {
  // Call normalizer.normalize(...)
}

And call it like this:

parsing(/* something here */, normalizeValFunc(min, max, floor, ceiling))

In Java 8, you can avoid the anonymous class and just use a lambda instead:

public static normalizeValFunc(final int min, final int max, final int floor, final int ceiling) {
    return value -> /* Use min, max, floor, ceiling & value here to return something. */
}

You may as well do this inline:

parsing(/* something here */, value -> /* an expression using min, max, floor, ceiling, value */)

Also, rather than define a Normalizer, you can just use the standard IntUnaryOperator functional interface (and call applyAsInt instead of normalize).

Ismail Badawi
  • 36,054
  • 7
  • 85
  • 97