英文:
How to avoid code redundancy with JAVA generics
问题
以下是您要翻译的内容:
我有两个类似的函数,它们向不同的API发送不同的请求:
// 填充请求
CompletableFuture<ReqType1> future = new CompletableFuture<>();
RpcClientController rpcClientController = new RpcClientController();
service1.api1(rpcClientController, request1, future::complete);
RspType1 response;
try {
if (rpcClientController.isFailed()) {
log.error();
return null;
}
response = future.get(5, TimeUnit.SECONDS);
if (response == null) {
log.error();
return null;
}
} catch (InterruptedException e) {
log.error("error: {}", e.getMessage());
return null;
} catch (ExecutionException e) {
log.error("error: {}", e.getMessage());
return null;
} catch (TimeoutException e) {
log.error("error: {}", e.getMessage());
return null;
}
// 处理响应
另一个:
// 填充请求
CompletableFuture<ReqType2> future = new CompletableFuture<>();
RpcClientController rpcClientController = new RpcClientController();
service2.api2(rpcClientController, request2, future::complete);
RspType2 response;
try {
if (rpcClientController.isFailed()) {
log.error();
return null;
}
response = future.get(5, TimeUnit.SECONDS);
if (response == null) {
log.error();
return null;
}
} catch (InterruptedException e) {
log.error("error: {}", e.getMessage());
return null;
} catch (ExecutionException e) {
log.error("error: {}", e.getMessage());
return null;
} catch (TimeoutException e) {
log.error("error: {}", e.getMessage());
return null;
}
// 处理响应
在C++中,可以使用一个template
方法来处理这种情况。我认为C++编译器会分别为<ReqType1,RspType1,SrvType1,ApiFunc1>和<ReqType2,RspType2,SrvType2,ApiFunc2>创建两种方法。
然而,在Java中,无法正确编译以下代码:
protected <Request, Service, Response>
Response callService(Request request, Service service, Response response) {
...
service.api1(rpcClientController, request, future::complete);
// 错误,无法解析方法 'api1' 在 'service' 中
}
看起来泛型类型Service
对于Java编译器来说与Object
相同。那么通常泛型方法是什么样的呢?
英文:
I have two similar functions which send different requests to different APIs:
// fill request
CompletableFuture<ReqType1> future = new CompletableFuture<>();
RpcClientController rpcClientController = new RpcClientController();
service1.api1(rpcClientController, request1, future::complete);
RspType1 response;
try {
if (rpcClientController.isFailed()) {
log.error();
return null;
}
response = future.get(5, TimeUnit.SECONDS);
if (response == null) {
log.error();
return null;
}
} catch (InterruptedException e) {
log.error("error: {}", e.getMessage());
return null;
} catch (ExecutionException e) {
log.error("error: {}", e.getMessage());
return null;
} catch (TimeoutException e) {
log.error("error: {}", e.getMessage());
return null;
}
// process response
The other:
// fill request
CompletableFuture<ReqType2> future = new CompletableFuture<>();
RpcClientController rpcClientController = new RpcClientController();
service2.api2(rpcClientController, request2, future::complete);
RspType2 response;
try {
if (rpcClientController.isFailed()) {
log.error();
return null;
}
response = future.get(5, TimeUnit.SECONDS);
if (response == null) {
log.error();
return null;
}
} catch (InterruptedException e) {
log.error("error: {}", e.getMessage());
return null;
} catch (ExecutionException e) {
log.error("error: {}", e.getMessage());
return null;
} catch (TimeoutException e) {
log.error("error: {}", e.getMessage());
return null;
}
// process response
A template
method in C++ can handle this. I think C++ compiler creates two methods for <ReqType1, RspType1, SrvType1, ApiFunc1> and <ReqType2, RspType2, SrvType2, ApiFunc2>, respectively.
Nevertheless, this cannot be compiled properly in Java:
protected <Request, Service, Response>
Response callService(Request request, Service service, Response response) {
...
service.api1(rpcClientController, request, future::complete);
// wrong, cannot resolve method 'api1' in 'service'
}
It seems that generic type Service
is the same as Object
to Java compiler. So what does a generic method usually look like?
答案1
得分: 2
你的实现已经很接近了,但你声明类型参数的方式是不正确的。应该更像这样:
protected <T extends Request, S extends Service, R extends Response>
Response callService(T request, S service, R response) {
...
service.api1(rpcClientController, request, future::complete);
}
按照惯例,在 Java 中,类型参数通常是一个大写字母。为了让它们按照你的期望行为工作,你需要限定类型;因此使用了 extends
。
英文:
You're pretty close with this, the way you've declared your type parameters is incorrect though. It should be more like:
protected <T extends Request, S extends Service, R extends Response>
Response callService(T request, S service, R response) {
...
service.api1(rpcClientController, request, future::complete);
}
By convention in Java type parameters are a single uppercase letter. To get them to behave as you expect you need to bound the types; hence the extends
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论