Yegoshin Maxim
Yegoshin Maxim

Reputation: 881

Java. Reuse try-finally construction with return

Look at this code:

IDfSessionManager manager = DfcSessionManager.getSessionManager();
    try {
        IDfSession session = manager.getSession(DfsUtils.getCurrentRepository());
        ...
        return somewhat; //May be without return statement
    } finally {
        if (session != null) {
            manager.release(session);
        }
    }

Such construction repeats many times and surrounds different code. This can be a method with or without return statement. I want to make something reusable of this try-finally block.

I've think out of such realization.

public abstract class ISafeExecute<T> {

private IDfSession session = null;

protected abstract T execute() throws DfException;

public T executeSafely() throws Exception {
    IDfSessionManager manager = DfcSessionManager.getSessionManager();
    try {
        session = manager.getSession(DfsUtils.getCurrentRepository());
        return execute();
    } finally {
        if (session != null) {
            manager.release(session);
        }
    }
}

public IDfSession getSession() {
    return session;
}

}

Session field was made with public getter.

And we can use this class like this(with returned object):

return new ISafeExecute<String>() {
        @Override
        public String execute() throws DfException {
            return getSession().getLoginTicket();
        }
    }.executeSafely();

Or without return object:

    new ISafeExecute() {
        @Override
        public Object execute() {
            someMethod();
            return null;
        }
    }.executeSafely();

Upvotes: 3

Views: 2855

Answers (2)

Yegoshin Maxim
Yegoshin Maxim

Reputation: 881

I've come to such decision:

 public abstract class SafeExecute<T> {

    protected IDfSession session = null;

    public T executeSafely() throws Exception {
        IDfSessionManager manager = DfcSessionManager.getSessionManager();
        try {
            session = manager.getSession(DfsUtils.getCurrentRepository());
            return logic();
        } finally {
            if (session != null) {
                manager.release(session);
            }
        }
    }

    protected abstract T logic() throws Exception;

}

Then by extending this class:

public class Service extends SafeExecute<String> {

    public String getLoginTicket() throws Exception {
        return executeSafely();
    }

    @Override
    protected String logic() throws Exception {
        //TODO implement
    }
}

Upvotes: 0

Matthias Meid
Matthias Meid

Reputation: 12523

You can use Runnable<T> to build a mechanism to do this (sort of injecting a function into another function):

public void runInSession(Runnable<IDfSession> runnable) {

    IDfSession session = null;
    try {

        session = manager.getSession(DfsUtils.getCurrentRepository());
        runnable.run(session);        

    } finally {
        if (session != null) {
            manager.release(session);
        }
    }

}

You could use more generics to enable you to return values as well. I'm lacking a Java compiler here and I'm a bit unsure about the syntax though.

Edit, as I see your edits:

Using a custom ISafeExecute interface may be even neater than using Runnable<T>, but the idea remains the same. You can built it so that a return value (or error) can be places elegantly:

interface ISafeExecute<T> {

  void execute(IDfSession session);

  T getResult();

  Exception getException();

}

mySafeExecute.execute(session);

if(mySafeExecute.getException() == null) {
    return mySafeExecute.getResult();
} else {
    // runtime exception or declaration in method
    // signature
    throw new RuntimeException(mySafeExecute.getException());
}

Upvotes: 5

Related Questions