2
votes

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.

1
Nice reference. Would upvote you if I had enough reputation. - Scott Emmons
You need closures. Lambdas make it easy, but unfortunately anonymous class route is the only way in pre-Java 8. See this, this etc - nawfal

1 Answers

5
votes

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).