在java

时间:2018-05-23 12:40:28

标签: java

我向Web服务发送了多个请求,下面有一个请求示例。对于我的应用程序来说,从Web服务获得答案非常重要,因此如果有异常应用程序将尝试多次以获得答案。

因为这样可以获得简单的东西 deviceList = serviceAdapter.getDevices();变为下面的代码。

boolean flag = true;
int counter = 1;
List<Device> deviceList = null;

while (flag) {
   try {
        deviceList  = serviceAdapter.getDevices(); 
        flag = false;
   } catch (Exception e) {
           try {
                if (counter == 5) {
                    System.out.println("Timeout Occured!");
                    flag = false;
                } else {
                    Thread.sleep(1000 * counter);
                    counter++;
                }
            } catch (InterruptedException e1) {
            }
    }
}

在我的应用程序中,我有很多请求,这意味着会有更多丑陋的代码。有没有办法我将我的请求方法作为参数调用另一种方法,如下所示:

deviceList = wrapperMethod(serviceAdapter.getDevices());

问题是会有不同类型的请求,因此它们将返回不同类型的对象(列表,数组,字符串,整数),并且它们的参数将会改变。这个问题在java中是否有合适的解决方案?

4 个答案:

答案 0 :(得分:0)

您可以将Supplier<T>传递给wrapperMethod

public static <T> T wrapperMethod (Supplier<T> supp) {
    boolean flag = true;
    int counter = 1;
    T value = null;

    while (flag) {
       try {
            value = supp.get(); 
            flag = false;
       } catch (Exception e) {
           try {
                if (counter == 5) {
                    System.out.println("Timeout Occured!");
                    flag = false;
                } else {
                    Thread.sleep(1000 * counter);
                    counter++;
                }
            } catch (InterruptedException e1) {
            }
        }
    }
}

并将其命名为:

List<Device> deviceList = wrapperMethod (() -> serviceAdapter.getDevices());
但是,我担心它会限制你在lambda表达式中调用的方法只能抛出RuntimeException s。

答案 1 :(得分:0)

您可以使用jcabi-aspects

中的@RetryOnFailure注释

创建一个包装器方法,然后对其进行注释以在异常时启用自动重试

举个例子:

@RetryOnFailure(attempts = 5)
List<Device> retryWhenFailed(ServiceAdapter serviceAdapter) throws Exception {
    return serviceAdapter.getDevices();
}

答案 2 :(得分:0)

您可以使用某些命令实现来执行某些特定代码:

这是一个简单的命令示例

class SayHello implements Command{
    @Override
    public void run() {System.out.println("Hello World");}
}

class KillMe implements Command{
    public void run() { throw new RuntimeException();};
}

还有几个实现:

Command

执行这些方法所需要做的就是接收public static void execCommand(Command cmd) { cmd.run(); } 的实例并运行方法:

public static void main(String[] args) {
    execCommand(new SayHello());
    execCommand(new KillMe());
}

并使用此

execCommand(() -> System.out.println("Say goodbye"));
  

Hello World
  线程&#34; main&#34;中的例外情况了java.lang.RuntimeException

它也接受lambda表达式:

public class Test{
    public static void testMe() {
        System.out.println("I work");
    }
}

execCommand(Test::testMe);

方法参考:

Exception

请注意,我没有指定这可能会抛出RuntimeException因此我仅限于void run() throws Exception之类的未经检查的异常,但当然public class Test { public static void main(String[] args) { try { execCommand(new SayHello()); execCommand(() -> System.out.println("Say goodbye")); execCommand(Test::testMe); execCommand(new KillMe()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void testMe() throws IOException{ System.out.println("I work"); } public static void execCommand(Command cmd) throws Exception { cmd.run(); } } interface Command{ void run() throws Exception; } class SayHello implements Command{ @Override public void run() {System.out.println("Hello World");} } class KillMe implements Command{ public void run() { throw new RuntimeException();}; } 可能是一个解决方案。这样你就可以做任何你想做的事。

完整示例(有例外):

Hello World  
Say goodbye  
I work  
Exception in thread "main" java.lang.RuntimeException  
    at main.KillMe.run(Test.java:39)  
    at main.Test.execCommand(Test.java:25)
    at main.Test.main(Test.java:17)

输出:

my_class

答案 3 :(得分:0)

此解决方案使用Generics能够处理具有大多数相同代码的不同Object和Runnable来执行提取。

使用此解决方案,你只需要编写从ServiceAdapter<T extends Fetchable>,以实现撷取针对每个不同的类中的数据的逻辑延伸的不同的适配器(这将具有实施Fetchable)。

定义一个接口,用于删除不同服务可以获取的对象。

package so50488682;

public interface Fetchable {

}

要检索的ojbect实现此接口,因此您可以对不同的类使用相同的代码。

package so50488682;

public class Device implements Fetchable{
    private String  id;

    public Device(String id) {
        this.id = id;
    }
    public String toString() {
        return "I am device " + id;
    }

}

定义一个抽象ServiceAdapter,不同的服务适配器将扩展该抽象throws Exception以实现要检索的每种对象的逻辑。我们将FetcherService添加到get()方法中,因此此方法只是将异常处理委托给package so50488682; import java.util.List; public abstract class ServiceAdapter<T extends Fetchable> { public abstract List<T> get() throws Exception; } 并确定它是否应该重试或失败。

package so50488682;

import java.util.ArrayList;
import java.util.List;

public class DeviceServiceAdapter extends ServiceAdapter<Device>{

    @Override
    public List<Device> get() throws Exception{

        List<Device> rtn = new ArrayList<>();

        // fetch the data and put it into rtn, this is a mock
        Device d = new Device("1");
        rtn.add(d);
        d = new Device("2");
        rtn.add(d);
        d = new Device("3");
        rtn.add(d);
        //

        return rtn;
    }

}

这是获取类Device对象的实现示例。

public class FetcherService<T extends Fetchable> implements Runnable{

    List<T> result = new ArrayList<>();
    ServiceAdapter<T> serviceAdapter;

    @Override
    public void run() {

        boolean flag = true;
        int counter = 1;

        while (flag) {
           try {
                result  = serviceAdapter.get(); 
                flag = false;
           } catch (Exception e) {
                   try {
                        if (counter == 5) {
                            System.out.println("Timeout Occured!");
                            flag = false;
                        } else {
                            Thread.sleep(1000 * counter);
                            counter++;
                        }
                    } catch (InterruptedException e1) {
                        throw new RuntimeException("Got Interrupted in sleep", e);
                    }
            }
        }
    }

    public List<T> getResult() {
        return result;
    }

    public void setResult(List<T> result) {
        this.result = result;
    }

    public void setAdapter(ServiceAdapter<T> adapter) {
        this.serviceAdapter = adapter;
    }

}

最后,这是运行不同服务适配器的通用解决方案。

package so50488682;

import java.util.List;

public class SO50488682 {

    public static void main(String args[]) {

        try {
            DeviceServiceAdapter deviceServiceAdapter = new DeviceServiceAdapter();


            FetcherService<Device> deviceFetcherService = new FetcherService<>();
            deviceFetcherService.setAdapter(deviceServiceAdapter);
            deviceFetcherService.run();
            List<Device> devices = deviceFetcherService.getResult();

            for(Device device : devices) {
                System.out.println(device.toString());
            }

        }catch(Exception e) {
            System.out.println("Exception after retrying a couple of times");
            e.printStackTrace();
        }
    }

}

从主程序或调用程序中它的工作原理如下:

{{1}}