user2434
user2434

Reputation: 6399

Passing function as argument in JDK 8

I am trying to refactor the below code

class FileDownloadResource{

   @Inject
   private FileDownload fileDownload;

    @Path(/abc)
    public Response downloadFileABC(){

         try{
              fileDownload.downloadABC();

         }catch(IOException e){

         }
          //Some code here that is common to the second method as well

    }

    @Path(/xyz)
     public Response downloadFileXYZ(){

         try{
              fileDownload.downloadXYZ();

         }catch(IOException e){
             //handle exception
         }
          //Some code here that is common to the first method as well

    }  
  }

The class is a JAX-RS rest resource. As you can see in the above code, everything except what is in the try block is the same for two method. Can we use any of the new JDK 8 features to pass fileDownload.downloadABC() as an argument to a private method ?

Basically, I am looking for some way to pass a function as an argument and let the other part of the code be same.

Upvotes: 1

Views: 664

Answers (2)

Tagir Valeev
Tagir Valeev

Reputation: 100209

Sure you can. You need either to use existing functional interface or create the new one. As you expect checked IOException, it's better to create the new one (you could also use Callable<Void>, but it's less convenient):

@FunctionalInterface
interface IORunnable {
    void run() throws IOException;
}

Now you can create generic request handler private method:

public Response handleRequest(IORunnable r){
     try {
         r.run();
     } catch(IOException e){
         // handle exception
     }
     //Common code follows
}

And use it like this:

@Path("/abc")
public Response downloadFileABC(){
    return handleRequest(fileDownload::downloadABC);
}

Or with lambda:

@Path("/abc")
public Response downloadFileABC(){
    return handleRequest(() -> fileDownload.downloadABC());
}

Upvotes: 4

Andreas
Andreas

Reputation: 159096

You can do this, as long as the downloadABC() and downloadXYZ() methods have the same parameters and return value as the download() method of the Download interface.

Name of interface and interface method can be anything you choose.

@FunctionalInterface
interface DownloadMethod {
    public void doDownload() throws IOException;
}

class FileDownload {
    public void downloadABC() throws IOException {}
    public void downloadXYZ() throws IOException {}
}

class FileDownloadResource{

    @Inject
    private FileDownload fileDownload;

    @Path("/abc")
    public Response downloadFileABC(){
        return download(fileDownload::downloadABC);
    }

    @Path("/xyz")
    public Response downloadFileXYZ() {
        return download(fileDownload::downloadXYZ);
    }

    private Response download(DownloadMethod method){
        try{
            method.doDownload();
        }catch(IOException e){
            //handle exception
        }
        //Some code here that is common to both methods
    }
}

Upvotes: 3

Related Questions