I integrated code to sonarqube for quality code and set method complexity is 4.
Please help me to reduce this for loop complexity to 4
for (int i = 1; i <= retryCount + count; i++) {
try {
if (cat!= null)
grps = cat.getAllGroups(category);
flag = true;
} catch (Exception e) {
if (i >= retryCount + count) {
throw new MyException(new Fault(1009,
new Object[] { e.getMessage() }));
} else {
if (e.getMessage().contains("No Records Found")) {
break;
} else {
String status = handleIOAutomationException(ctx, e);
if (status.equalsIgnoreCase("none")) {
throw new MyException(new Fault(1009,
new Object[] { e.getMessage() }));
} else if (status.equalsIgnoreCase("some")) {
}
}
}
}
if (flag) {
break;
}
}
Try to extract your logic into its own sub methods and try make these shorter. You should also try to make your identifiers more readable.
public void method() {
...
int maxLoops = retryCount + count;
for (int i = 1; i <= maxLoops; i++) {
if (tryToGetAllGroups(maxLoops, i))
break;
}
}
private boolean tryToGetAllGroups(int maxLoops, int i) throws MyException {
try {
if (cat != null)
grps = cat.getAllGroups(category);
return true;
} catch (Exception e) { // you should make Exception more specific!
if (i >= maxLoops) {
return throwFinalException(e);
} else {
if (tryToGetCat(e)) return true;
}
}
return false;
}
private boolean tryToGetCat(Exception e) throws MyException {
if (e.getMessage().contains("No Records Found")) {
return true;
} else {
String status = handleIOAutomationException(ctx, e);
if (status.equalsIgnoreCase("none")) {
throwFinalException(e);
} else if (status.equalsIgnoreCase("some")) {
// try to get cat here
}
}
return false;
}
private boolean throwFinalException(Exception e) throws MyException {
throw new MyException(new Fault(1009,
new Object[]{e.getMessage()}));
}
Is there a way to eliminate all the "if" statements from this class and still maintain the exact same functionality ?
So far I managed to simplify the code by creating the 2 extra functions: isNameValid and isPhoneValid, but I need a way to get rid of all the "if" statements.
public class ClientValidator implements Validator<Client> {
#Override
public void validate(Client entity) throws ValidatorException {
if(!isNameValid(entity.getName())){
throw new ClientException("Invalid name!");
}
if(!isPhoneValid(entity.getPhone())){
throw new ClientException("Invalid phone number!");
}
}
private boolean isNameValid(String name) {
return name.length() > 1 && name.length() < 100;
}
private boolean isPhoneValid(String phone) {
try {
Long.parseLong(phone);
} catch (NumberFormatException e) {
return false;
}
return true;
}
}
you can try optionals and do filtering on the methods, but you miss reason specific exceptions:
Optional
.of(entity)
.filter(entity -> isNameValid(entity.getName())
.filter(entity -> isPhoneValid(entity.getPhone())
.orElseThrow(() -> new ClientException("Wrong client data"));
Is there a way to eliminate all the "if" statements from this class and still maintain the exact same functionality ?
Yes. It's a hack, but if isn't the only flow-control. Easiest I see, a while loop with the same logic. Like,
#Override
public void validate(Client entity) throws ValidatorException {
while (!isNameValid(entity.getName())) {
throw new ClientException("Invalid name!");
}
while (!isPhoneValid(entity.getPhone())) {
throw new ClientException("Invalid phone number!");
}
}
You could also use switch statements like
#Override
public void validate(Client entity) throws ValidatorException {
switch (isNameValid(entity.getName())) {
case false:
throw new ClientException("Invalid name!");
}
switch (isPhoneValid(entity.getPhone())) {
case false:
throw new ClientException("Invalid phone number!");
}
}
What about this :
#Override
public void validate(String entity) throws ClientException {
String message = !isNameValid(entity.getName()) ? "Invalid name!"
: !isPhoneValid(entity.getPhone()) ? "Invalid phone number!" : "";
Stream.of(message).filter(m -> m.isEmpty()).findAny()
.orElseThrow(() -> new ClientException (message));
}
I could think of some dirty tricks like
public void validate(Client entity) throws ValidatorException {
try {
int len = entity.getName().length();
int isshort = 1 / len;
int islong = 1 / max (0, 100- length);
} catch (Exception e) {
throw new ClientException("Invalid name!");
}
try {
Long.parseLong(entity.getPhone());
} catch (NumberFormatException e) {
throw new ClientException("Invalid phone number!");
}
}
So no if needed
How could I move most of the code into one function or otherwise consolidate it? I'm not so happy with so much duplicate code. Event IntelliJ complains about it...
public boolean closeTrade(Trade trade) {
for (int i=0; i< NUM_CHECKS; i++) {
if (closeBrokerTrade(trade)) return true; // quit loop if successfully closed
//region sleep between checks
if (i < NUM_CHECKS -1) try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
throw propagate(e);
}
//endregion
}
return false;
}
public boolean closeTrade(String ticket) {
for (int i=0; i< NUM_CHECKS; i++) {
if (closeBrokerTrade(ticket)) return true; // quit loop if successfully closed
//region sleep between checks
if (i < NUM_CHECKS -1) try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
throw propagate(e);
}
//endregion
}
return false;
}
protected abstract boolean closeBrokerTrade(Trade trade);
protected abstract boolean closeBrokerTrade(String ticket);
In Java 8 you could pass the correct version of closeBrokerTrade as a lambda:
Declare the function like this:
public boolean closeTrade( BooleanSupplier f) {
// ...
if (f.getAsBoolean()) return true; // quit loop if successfully closed
// ...
return false;
}
And call it like that:
c.closeTrade( () -> c.closeBrokerTrade(new Trade()) );
c.closeTrade( () -> c.closeBrokerTrade("123") );
I need to see the implementation of closeBrokerTrade to be sure about the behaviour, but I would do something like this:
public boolean closeTrade(Trade trade) {
String ticket = ...// generate ticket from trade in whatever way you do it, e.g. trade.getTicket() or trade.toString(), etc. etc.
return closeTrade(ticket);
}
public boolean closeTrade(String ticket) {
for (int i=0; i< NUM_CHECKS*3; i++) {
if (closeBrokerTrade(ticket)) return true; // quit loop if successfully closed
//region sleep between checks
if (i < NUM_CHECKS -1) try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
throw propagate(e);
}
//endregion
}
return false;
}
Correct me if I am wrong or if it is the case that you obtain the trade from the ticket.
If that's not possible, here is my suggestion:
Use generics to represent parameterized trade closing classes like this:
public abstract class ClosingTradeStrategy<T> {
public boolean closeTrade(T trade) {
for (int i=0; i< NUM_CHECKS*3; i++) {
if (closeBrokerTrade(trade)) return true; // quit loop if successfully closed
//region sleep between checks
if (i < NUM_CHECKS -1) try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
throw propagate(e);
}
//endregion
}
return false;
}
protected abstract boolean closeBrokerTrade(T trade);
}
then you can use this to implement different trade closing strategies like this:
public class StringClosingTradeStrategy extends ClosingTradeStrategy<String> {
#Override
protected boolean closeBrokerTrade(String trade) {
... // implement
}
}
public class TradeClosingTradeStrategy extends ClosingTradeStrategy<Trade> {
#Override
protected boolean closeBrokerTrade(Trade trade) {
... // implement
}
}
The advantage of the second approach is that it is easily extensible to other closing strategies.
Use interfaces, as you would if you were to use a Comparator<T>:
private static interface CloseBrokerTradeChecker <T> {
boolean closeBrokerTrade(T t);
}
private static class CloseBrokerTradeCheckerTrade
implements CloseBrokerTradeChecker<Trade> {
#Override
boolean closeBrokerTrade(Trade trade) { ... }
}
private static class CloseBrokerTradeCheckerTicket
implements CloseBrokerTradeChecker<String> {
#Override
boolean closeBrokerTrade(String ticket) { ... }
}
private <T> boolean closeTrade(T t, CloseBrokerTradeChecker<T> checker) {
for (int i=0; i< NUM_CHECKS*3; i++) {
if (checker.closeBrokerTrade(t)) return true; // quit loop if successfully closed
//region sleep between checks
if (i < NUM_CHECKS -1) try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
throw propagate(e);
}
//endregion
}
return false;
}
public boolean closeTrade(Trade trade) {
// TODO: extract CloseBrokerTradeCheckerTrade as a static final variable
return closeTrade(trade, new CloseBrokerTradeCheckerTrade());
}
public boolean closeTrade(String ticket) {
return closeTrade(ticket, new CloseBrokerTradeCheckerTicket());
}
From working with EMMA I have noticed that it fails to instrument correctly causing the class to become mangled. Below is a simple example highlighting this issue.
public void showProblem() {
try {
for (int i = 0; i > 10; i++) {
System.out.println(i);
}
} catch (final Throwable e) {
System.err.println(e);
}
}
Instrumented class
public void showProblem()
{
boolean[][] tmp3_0 = $VRc; if (tmp3_0 == null) tmp3_0; boolean[] arrayOfBoolean = $VRi()[1]; int i = 0; arrayOfBoolean[0] = true; tmpTernaryOp = tmp3_0;
try
{
do
{
Throwable e;
System.out.println(e);
e++; arrayOfBoolean[1] = true; arrayOfBoolean[2] = true; } while (e > 10); arrayOfBoolean[3] = true;
}
catch (Throwable localThrowable1)
{
System.err.println(localThrowable1); arrayOfBoolean[4] = true;
}
arrayOfBoolean[5] = true;
}
Notice that it is attempting to increment e of type Throwable and using this within the while loop.
I have found that by moving the try catch logic within the for loop it resolves this. As highlighted in the below code.
public void showProblem() {
for (int i = 0; i > 10; i++) {
try {
System.out.println(i);
} catch (final Throwable e) {
System.err.println(e);
}
}
}
Instrumented class
public void showProblem()
{
boolean[][] tmp3_0 = $VRc; if (tmp3_0 == null) tmp3_0; boolean[] arrayOfBoolean = $VRi()[1]; int i = 0;
Throwable e;
arrayOfBoolean[0] = true; tmpTernaryOp = tmp3_0;
do {
try { System.out.println(i); arrayOfBoolean[1] = true;
} catch (Throwable localThrowable1) {
System.err.println(localThrowable1); arrayOfBoolean[2] = true;
}
i++; arrayOfBoolean[3] = true; arrayOfBoolean[4] = true; } while (i > 10);
arrayOfBoolean[5] = true;
}
Has anyone else experienced these issues?
Setup
Windows 7 64
Java 1.6.0_24 64-bit
Emma v2.0, build 5312
Solution
So it turned out that the problem was to do with the debug information that eclipse was building into the classes. This was observed when using the Android generated ant scripts to execute javac and similarly caused the problem. Disabling this enabled EMMA to successfully process the class files.
I hope this information will help others.
I have tested under Windows XP with Java JRE 1.6.0_35 and EMMA 2.0.5312 without any problems. For me the decompiled code (using JAD) looks like this:
public void showProblem()
{
boolean aflag[] = ($VRc != null ? $VRc : $VRi())[2];
try
{
int i = 0;
aflag[0] = true;
do
{
aflag[2] = true;
if (i > 10)
{
System.out.println(i);
i++;
aflag[1] = true;
} else
{
break;
}
} while (true);
aflag[3] = true;
}
catch (Throwable throwable)
{
System.err.println(throwable);
aflag[4] = true;
}
aflag[5] = true;
}
P.S.: I think in your code sample you actually wanted to use i < 10 in the for loop, not i > 10, didn't you? ;-) Anyway, I used your code just as to make sure to reproduce your situation.
I'm writing some reconnect logic to periodically attempt to establish a connection to a remote endpoint which went down. Essentially, the code looks like this:
public void establishConnection() {
try {
this.connection = newConnection();
} catch (IOException e) {
// connection failed, try again.
try { Thread.sleep(1000); } catch (InterruptedException e) {};
establishConnection();
}
}
I've solved this general problem with code similar to the above on many occasions, but I feel largely unsatisfied with the result. Is there a design pattern designed for dealing with this issue?
Shameless plug: I have implemented some classes to allow retrying operations. The library is not made available yet, but you may fork it on github.
And a fork exists.
It allows building a Retryer with various flexible strategies. For example:
Retryer retryer =
RetryerBuilder.newBuilder()
.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECOND))
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.retryIfExceptionOfType(IOException.class)
.build();
And you can then execute a callable (or several ones) with the Retryer:
retryer.call(new Callable<Void>() {
public Void call() throws IOException {
connection = newConnection();
return null;
}
}
You could try the Idempotent Retry Pattern.
I really like this Java 8 code from this blog and you don't need any extra library on your classpath.
You only need to pass a function to the retry class.
#Slf4j
public class RetryCommand<T> {
private int maxRetries;
RetryCommand(int maxRetries)
{
this.maxRetries = maxRetries;
}
// Takes a function and executes it, if fails, passes the function to the retry command
public T run(Supplier<T> function) {
try {
return function.get();
} catch (Exception e) {
log.error("FAILED - Command failed, will be retried " + maxRetries + " times.");
return retry(function);
}
}
private T retry(Supplier<T> function) throws RuntimeException {
int retryCounter = 0;
while (retryCounter < maxRetries) {
try {
return function.get();
} catch (Exception ex) {
retryCounter++;
log.error("FAILED - Command failed on retry " + retryCounter + " of " + maxRetries, ex);
if (retryCounter >= maxRetries) {
log.error("Max retries exceeded.");
break;
}
}
}
throw new RuntimeException("Command failed on all of " + maxRetries + " retries");
}
}
And to use it:
new RetryCommand<>(5).run(() -> client.getThatThing(id));
Using Failsafe (author here):
RetryPolicy retryPolicy = new RetryPolicy()
.retryOn(IOException.class)
.withMaxRetries(5)
.withDelay(1, TimeUnit.SECONDS);
Failsafe.with(retryPolicy).run(() -> newConnection());
No annotations, no magic, doesn't need to be a Spring app, etc. Just straightforward and simple.
I'm using AOP and Java annotations. There is a ready-made mechanism in jcabi-aspects (I'm a developer):
#RetryOnFailure(attempts = 3, delay = 1, unit = TimeUnit.SECONDS)
public void establishConnection() {
this.connection = newConnection();
}
ps. You can also try RetryScalar from Cactoos.
You can try spring-retry, it has a clean interface and it's easy to use.
Example:
#Retryable(maxAttempts = 4, backoff = #Backoff(delay = 500))
public void establishConnection() {
this.connection = newConnection();
}
In case of exception, it will retry (call) up to 4 times the method establishConnection() with a backoff policy of 500ms
You can also create a wrapper function that just does a loop over the intended operation and when is done just break out of the loop.
public static void main(String[] args) {
retryMySpecialOperation(7);
}
private static void retryMySpecialOperation(int retries) {
for (int i = 1; i <= retries; i++) {
try {
specialOperation();
break;
}
catch (Exception e) {
System.out.println(String.format("Failed operation. Retry %d", i));
}
}
}
private static void specialOperation() throws Exception {
if ((int) (Math.random()*100) % 2 == 0) {
throw new Exception("Operation failed");
}
System.out.println("Operation successful");
}
If you are using java 8, this may helps.
import java.util.function.Supplier;
public class Retrier {
public static <T> Object retry(Supplier<T> function, int retryCount) throws Exception {
while (0<retryCount) {
try {
return function.get();
} catch (Exception e) {
retryCount--;
if(retryCount == 0) {
throw e;
}
}
}
return null;
}
public static void main(String[] args) {
try {
retry(()-> {
System.out.println(5/0);
return null;
}, 5);
} catch (Exception e) {
System.out.println("Exception : " + e.getMessage());
}
}
}
Thanks,
Praveen R.
I'm using retry4j library. Test code example:
public static void main(String[] args) {
Callable<Object> callable = () -> {
doSomething();
return null;
};
RetryConfig config = new RetryConfigBuilder()
.retryOnAnyException()
.withMaxNumberOfTries(3)
.withDelayBetweenTries(5, ChronoUnit.SECONDS)
.withExponentialBackoff()
.build();
new CallExecutorBuilder<>().config(config).build().execute(callable);
}
public static void doSomething() {
System.out.println("Trying to connect");
// some logic
throw new RuntimeException("Disconnected"); // init error
// some logic
}
Here's a another approach to perform the retry. No libraries, no annotations, no extra implementations. Import java.util.concurrent.TimeUnit;
public static void myTestFunc() {
boolean retry = true;
int maxRetries = 5; //max no. of retries to be made
int retries = 1;
int delayBetweenRetries = 5; // duration between each retry (in seconds)
int wait = 1;
do {
try {
this.connection = newConnection();
break;
}
catch (Exception e) {
wait = retries * delayBetweenRetries;
pause(wait);
retries += 1;
if (retries > maxRetries) {
retry = false;
log.error("Task failed on all of " + maxRetries + " retries");
}
}
} while (retry);
}
public static void pause(int seconds) {
long secondsVal = TimeUnit.MILLISECONDS.toMillis(seconds);
try {
Thread.sleep(secondsVal);
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
there is nothing special in retrying at all - take this class as example http://www.docjar.com/html/api/org/springframework/jms/listener/DefaultMessageListenerContainer.java.html
As you can see even spring developers still writing code for retry-ing - line 791...
there is no such special pattern AFAIK..
What i can advice to deal with resources is to take apache commons pool library - check this http://commons.apache.org/pool/apidocs/org/apache/commons/pool/impl/GenericObjectPool.html and visit http://commons.apache.org/pool
I have wrote my custom annotation. Maybe you can use this annotation.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface RetryOperation {
int retryCount();
int waitSeconds();
}
#Slf4j
#Aspect
#Component
public class RetryOperationAspect {
#Around(value = "#annotation(com.demo.infra.annotation.RetryOperation)")
public Object retryOperation(ProceedingJoinPoint joinPoint) throws Throwable {
Object response = null;
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
RetryOperation annotation = method.getAnnotation(RetryOperation.class);
int retryCount = annotation.retryCount();
int waitSeconds = annotation.waitSeconds();
boolean successful = false;
do {
try {
response = joinPoint.proceed();
successful = true;
} catch (Exception e) {
log.error("Operation failed, retries remaining: {}", retryCount);
retryCount--;
if (retryCount < 0) {
throw e;
}
if (waitSeconds > 0) {
log.warn("Waiting for {} second(s) before next retry", waitSeconds);
Thread.sleep(waitSeconds * 1000L);
}
}
} while (!successful);
return response;
}
}
#RetryOperation(retryCount = 5, waitSeconds = 1)
public void method() {
}