15

I have a class that looks like this:

class A {
    public void method1(){
        iniCall();

        // Do something
        finalCall();
    }

    public void method2(){
        iniCall();

        // Do something different
        finalCall();
    } // ... more methods like this
}

How can I simplify this iniCall and finalCall so not to write them in every function (or several functions)?

Is it possible to do something like call(method1), being call something like this:

public void call(method){
    iniCall();
    method();
    finalCall();
}

Otherwise, what is a good alternative?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
zurfyx
  • 31,043
  • 20
  • 111
  • 145

5 Answers5

12

EDIT I see that my answer raises some questions.

The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread.

So creation of an instance of this interface may lead to uncertainty and questions. As suggested in comments, you may want to write your own interface and use it instead. It may be something like this:

public interface Method {
    public void run();
}

Your call method will change to something like this:

public void call(Method method) {
    iniCall();
    method.run();
    finalCall();
}

And your call to this method will be something like this:

call(new Method() {
    public void run() {
        // do your stuff here
    }
});

I suggest that you use similar design or consider using of a Template pattern which will probably require some refactoring.

Yury Fedorov
  • 14,508
  • 6
  • 50
  • 66
  • 2
    Regarding the edited addition: The recommendation in the JavaDocs does **not** imply that every runnable should be executed in an own thread! And in fact, this should certainly **not** be done here, because then, for example, `finalCall` may be called before `// do something` was finished. – Marco13 Dec 15 '15 at 16:52
  • 2
    I wont be down-voting but I am sorry - "[The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread](http://docs.oracle.com/javase/7/docs/api/java/lang/Runnable.html)". Using it likes this will just look like an error to anyone who looks at it in future. Declare your own class and call it's method. Runnable was not designed for this. – Rudi Kershaw Dec 15 '15 at 17:47
  • I agree with all the downvoters, actually, and I improved my answer by providing an alternative – Yury Fedorov Dec 15 '15 at 18:03
  • 3
    @RudiKershaw and Orlangure Runnable may have originally been designed for use with threads, but that is no longer its only intended purpose; see [this comment by Brian Goetz.](http://stackoverflow.com/questions/26504594/functional-callback-in-java-8?lq=1#comment41657813_26504594) – Alex - GlassEditor.com Dec 15 '15 at 22:03
  • 1
    I'd **strongly** suggest to roll back to [Revision 1](http://stackoverflow.com/revisions/34293035/1). Everything else is just confusing. The threading thing is completely unrelated and may confuse future readers (and cause garbage when they actually *do* create a thread there), and the own interface with the own `run` method is simply not necessary, as `Runnable` is now used in a broader scope (which is confirmed by the comment by Brian Goetz that Alex linked to). – Marco13 Dec 16 '15 at 12:07
12

You can use a lambda expression (or anonymous class instance that implements Runnable if you don't use Java 8) :

public void call(Runnable method){
    iniCall();
    method.run();
    finalCall();
}

...

public void someMethod () {

    call (() -> {
                   // do something
                });
    ...
    call (() -> {
                   // do something different
                });

}
Eran
  • 387,369
  • 54
  • 702
  • 768
  • side note: since the called method is apparently without parameters, a reference can be used: `myInstance::myMethod` – njzk2 Dec 15 '15 at 21:14
5

Similar to the other suggestions (who are much quicker than me - but I always want to provide a running example...), I'd suggest passing a Runnable instance to a method that generically calls iniCall(), executes the Runnable and then calls finalCall().

The actual work may be passed in as dedicated Runnable instances, lambdas or method references - the latter is shown here:

public class RepeatedMethodContents
{
    public static void main(String[] args)
    {
        RepeatedMethodContents r = new RepeatedMethodContents();
        r.callWrapped(r::doSomething);
        r.callWrapped(r::doSomethingDifferent);
    }

    private void callWrapped(Runnable runnable)
    {
        iniCall();
        runnable.run();
        finalCall();
    }

    private void doSomething()
    {
        System.out.println("doSomething");
    }

    private void doSomethingDifferent()
    {
        System.out.println("doSomethingDifferent");
    }

    private void iniCall()
    {
        System.out.println("ini");
    }

    private void finalCall()
    {
        System.out.println("final");
    }

}

The output is, as desired:

ini
doSomething
final
ini
doSomethingDifferent
final

BTW: I'd be hesitant to use reflection in general for things like this. Most often, there is an easier, more straightforward and less error-prone way.

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • I would have upvoted that answer if it wasn't for the return *before* the `{`. – njzk2 Dec 15 '15 at 21:16
  • 1
    @njzk2 Sorry, what do you mean? There is no `return` in the code at all...?! EDIT: You aren't referring to the *formatting*, are you?! – Marco13 Dec 16 '15 at 10:26
0

In Java you can't pass methods as argument. You could pass a Runnable though:

public void method1() {
    call(new Runnable() {
        @Override
        public void run() {
            //do something
        }
    });
}

public void method2() {
    call(new Runnable() {
        @Override
        public void run() {
            //do something different
        }
    });
}

public void call(Runnable runnable){
    iniCall();
    runnable.run();
    finalCall();
}

However, I really don't like this approach. I think you could apply template design patter.

Héctor
  • 24,444
  • 35
  • 132
  • 243
0

I'm not sure I like the use of Runnable in the context others have used. Typically, I think of Runnable as something that will run in a thread, executor service, etc. And to back that up is the documentation:

The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread.

But making something that does the same thing from scratch is really simple and quick. We can make an abstract class that will hold the structure you need:

public abstract class AbstractClass
{
    private void iniCall() { ... } // Could also be abstract

    private void finalCall() { ... } // Could also be abstract

    public void doTheThing()
    {
        iniCall();
        foo();
        finalCall();
    }

    public abstract void foo();
}

Of course you need to come up with better names, but that's the starting point. Then we have two options: instantiate an anonymous class built by extending this class, or creating a new concrete class. Here's the example of using an anonymous class:

AbstractClass a = new AbstractClass()
    {
        @Override
        public void foo()
        {
            // Place an implementation here.
            method(); // one example, based on the OP.
        }
    };
a.doTheThing();

And here's how you would do an actual class:

public class ConcreteClass extends AbstractClass
{
    @Override
    public void foo()
    {
        // Place an implementation here.
    }
}
ConcreteClass c = new ConcreteClass();
c.doTheThing();

I mainly wanted to bring this up so that you could have a look at the 'anonymous class' paradigm, which is analogous to being able to pass functions as parameters. Other languages have pointers to functions, delegates, etc - well this is what Java has. The compiler will ensure that your anonymous class and concrete classes will have an implementation of foo, or it won't compile, so it's not something you can just go 'oops' and forget to implement.

Shaz
  • 1,376
  • 8
  • 18