sethvargo
sethvargo

Reputation: 26997

DRY up java (lambda functions?)

I'm writing a program in java that essentially tests a bunch of things...

For every call, I need to check for NullPointerExceptions, StackOverflow, IndexOutOfBounds, etc...

I have this repeating pattern in each of my methods now:

try {
  doSomething();
} catch(NullPointerExceptions npe) {
  // prints something
} catch(StackOverflow soe) {
  // prints something
} catch(IndexOutOfBounds iob) {
  // prints something
}

Since I may call doSomething() (with different params) multiple times in a single method, I can't just throw the exception back up to main (because I need the next test to actually run).

I'd like to write a lambda tester that I can pass a function to, but I can't find a way to do this with java :(.

I'd like to do something like:

private void test(Method m, E expectedValue) {
  try {
    if(!m.run().equals(expectedValue))
      System.out.println("FAILED TEST: "+m.name()+". Value was "+m.run()+", should have been "+expectedValue);
  } catch() {
    // see above
  }
}

Upvotes: 2

Views: 584

Answers (5)

dbyrne
dbyrne

Reputation: 61081

The best you can do in Java is to use an interface:

interface DoSomething<E extends Comparable<E>> {
  E doSomething();
}

Then your test method can look like this:

private void test(DoSomething<E> m, E expectedValue) {
  try {
    if(!m.doSomething().equals(expectedValue))
      System.out.println("FAILED TEST");
  } catch() {
    //handle exception
  }
}

E needs to extend Comparable<E> because you are calling equals inside of test.

This is called a SAM (single abstract method) interface. Using SAM classes and interfaces to simulate lambdas is a common occurence in Java. I've even heard them called "SAMbdas".

EDIT: My solution does not necessarily involve modifying existing classes:

DoSomething foo = new DoSomething<String>() {
     public String doSomething() { return "Hello World"; }
};
test(foo, "Hello World");

Upvotes: 4

Kojotak
Kojotak

Reputation: 2070

Lambdas are unfortunately not yet present in java. But you can use generic java.util.concurrent.Callable:

private <T> void test(Callable<T> c, T expectedValue) {
      try {
        if(!c.call().equals(expectedValue))
          System.out.println("FAILED TEST: "+c+". Value was "+c.call()+", should have been "+expectedValue);
      } catch(Exception ex) {
        // see above
      }
    }

Upvotes: 2

gmoore
gmoore

Reputation: 5566

Lambdas are going to work their way into JDK7. If you want to try it out, grab one of the early access releases from Oracle

http://www.jcp.org/en/jsr/detail?id=335

That said, I don't quite understand the problem. Can you add an example of how you intend to all these methods? Your suggested method sounds like it is on the right track, try:

private void test(Method m, Object target, Object[] args, E expectedValue) {
  try {
    if(!m.invoke(target, args).equals(expectedValue))
      System.out.println("FAILED TEST: "+m.name()+". Value was "+m.run()+", should have been "+expectedValue);
  } catch() {
    // see above
  }
}

Gus Bosman is right, though. A unit testing framework like JUnit would probably help a lothere.

Upvotes: 1

Guus Bosman
Guus Bosman

Reputation: 214

If you want to write this yourself, and not JUnit, you could use Reflection to call the method.

So, instead of saying m.run() you would use java.lang.reflect.Method#invoke:

try {
  method.invoke(obj, arg1, arg2,...);
} catch (Exception e) {
  // there are several Reflection exceptions you also need to deal with
}

Upvotes: 0

Ingo
Ingo

Reputation: 36349

It could go like this:

abstract class Method<R> {
     public R run();
}


test(new Method<Result1>() {
         public Result1 run() { .... }
     }, expectedResult);

Upvotes: 1

Related Questions