Repeat something until it succeeds, but at most 3 times - java

I have needed to program something like this several times since programming Java:
Do something that might fail. If it fails, try it again but at most 3 (or 2 or 5) times.
This approach should work:
for (int i = 0; i < 3; i++) {
try {
doSomething();
} catch(BadException e) {
continue;
}
break;
}
But I do not think that it is very expressive. Do you have a better solution?
Something like this would be nice:
try (maxTimes = 3) {
doSomething();
} catch(BadException e) {
retry;
}
Or:
try (maxTimes = 3) {
doSomething();
if(somethingFailed()) {
retry;
}
}
But this is not possible with Java. Do you know a language with which it is possible?

Java does not let you invent your own syntax, but you can define your own method to help you express the concept with less code:
public static boolean retry(int maxTries, Runnable r) {
int tries = 0;
while (tries != maxTries) {
try {
r.run();
return true;
} catch (Exception e) {
tries++;
}
}
return false;
}
Now you can call this method like this:
boolean success = retry(5, () -> doSomething());
// Check success to see if the action succeeded
// If you do not care if the action is successful or not,
// ignore the returned value:
retry(5, () -> doSomethingElse());
Demo.

Related

Break while loop only when all conditions in for loop are met

I would like to break a while loop only when all of the "bots" are upright. (*These bots being referred to are mini USB robots).
.upRight() returns true when a bot is standing and false when not.
public static boolean checkSomething() throws ... {
while (true) {
for (i = 0; i < bots; i++) { // bots = 2
if (!theMainBots[i].isUpright()) {
...
Thread.sleep(1000);
}
else {
return true;
}
}
}
The issue I'm facing, is that if the isUpright() method returns true for the first "bot", then all other bots are left unchecked and may return false. The intention is to wait for the user to place the bot in an upright position before proceeding.
You should check all the bots first, then act on the result. Don't try to act on the result inside the check loop.
Also, since the code doesn't return until all bots are upright, the method is misnamed and shouldn't return a value.
public static void waitUntilAllUpright() throws InterruptedException {
for (;;) { // forever loop
boolean allUpright = true;
for (i = 0; i < bots; i++) {
if (! theBots[i].isUpright()) {
allUpright = false;
break;
}
}
if (allUpright)
return;
System.out.println("Please ensure I'm upright");
Thread.sleep(500);
} // loop back to check all bots again
}
If you want to wait until the user makes the bot upright you could change the if to a while:
while (true) {
for (i = 0; i < bots; i++) { // bots = 2
while(!theBots[i].isUpright()) {
System.out.println("Please ensure I'm upright");
Thread.sleep(500);
}
}
return true;
}
This will loop through each element in the Array and while any given bot is not upright, it will loop and sleep until the bot is turned upright. In which case, you do not need to while(true) loop:
public static boolean checkUpright() throws InterruptedException {
for (i = 0; i < bots; i++) { // bots = 2
while(!theBots[i].isUpright()) {
System.out.println("Please ensure I'm upright");
Thread.sleep(500);
}
}
return true;
}
One way to achieve this, is using a variable that will determine when to leave the loop. Your problem here, is that you also need to change your for loop for a while loop. Why is that? Because you don't know if the bot you just checked was moved or not. Also, the outer loop is unnecessarily, unless you wanted to recheck again. So the code would end looking something like this.
public static boolean checkUpright() throws InterruptedException {
int counter = 0;
while (counter <= theBots.length) { // bots = 2
if (!theBots[i].isUpright()) {
System.out.println("Please ensure I'm upright");
Thread.sleep(500);
} else {
counter ++;
}
}
}
The context is not completely clear, but mixing logical control with user interaction might be the problem. Perhaps this approach might work:
public static boolean checkUpright() throws InterruptedException {
while (!areAllBotsUpright()) {
System.out.println("Please ensure I'm upright");
Thread.sleep(500);
}
}
public static boolean areAllBotsUpright() {
for (i = 0; i < bots; i++) {
if (!theBots[i].isUpright()) {
return false;
}
}
return true;
}
you can create a list from array of bots , iterate over this list using iterator
if a particular bot is upright , remove it from this list using iterator.remove.
outer while will run until list is not empty.
public static boolean checkUpright() {
ArrayList<Bot> notUprightBots= (ArrayList<Bot>) Arrays.asList(theBots);
while (!notUprightBots.isEmpty()) {
Iterator<Bot> iterator=notUprightBots.iterator();
while(iterator.hasNext()){
Bot bot=iterator.next();
if (!bot.isUpright()) {
System.out.println("Please ensure I'm upright");
try{
Thread.sleep(500);
}catch(InterruptedException e){
}
}else {
iterator.remove();
}
}
}
return true;
}

Java method references that take different numbers of characters?

I'm trying to apply retry logic to a number of methods. For example, I have method1(String) and method2(int, String) that I would like to retry up to a certain number of times.
I would ideally like:
int count = 0;
while (count < MAX_TRIES) {
try {
//run method
} catch (Exception e) {
//increment count
//throw e if count == MAX_TRIES
}
}
inside a method where I could pass in as a parameter method1 or method2. Is there any way to do this? Thanks!
Sure:
public <T> T retry(Callable<T> callable) throws Exception {
int count = 0;
while (true) {
try {
return callable.call();
} catch (Exception e) {
count++;
if (count == MAX_TRIES) {
throw(e);
}
}
}
}
And then
retry(() -> doSomething(a, b));
retry(() -> doSomethingElse(a));
This simple implementation is not very flexible, and could use better exception handling, though. You could use a library to do that (disclaimer: I'm the original author of this library), or at least see how it works and reuse some of its ideas.

I'm new in android studio & java , Lack of knowledge & logic to do Calculator. Need helps

I'm thinking how to do when I click the button first time it will show the result. After that i click the second time then the button will clear the result.
Example: First time Click, It will Calculate
R.id.Equal: calculate(true);
Calculate's Method
private void calculate(boolean IsEqualClick) {
String input = getinput();
try {
if (!isEmpty()) {
if (input.contains("x")) {
input.replaceAll("x", "*");
}
}
Expression expression = new ExpressionBuilder(input).build();
double result = expression.evaluate();
if (IsEqualClick) {
inputtext.setText(String.valueOf(twoDForm.format(result)));
resulttext.setText("");
} else {
resulttext.setText(String.valueOf(twoDForm.format(result)));
}
} catch (Exception e) {
stateError = true;
isNumber = false;
}
}
I can't think of how to write a code If i Click second time, it will delete. should I use the if statement again to progress it?
There is no need to check that isEqualClick if you have properly written the switch statement plus it is hardcoded so there is no meaning behind it.
Now for your solution do something like this:-
Declare a global variable boolean toCalculate = true;, this variable will check if we have to calculate or we have to clear the box;
Function call for calculate();
R.id.Equal: calculate();
The calculate() function:-
private void calculate() {
if (toCalculate) {
String input = getinput();
try {
if (!isEmpty()) {
if (input.contains("x")) {
input.replaceAll("x", "*");
}
}
Expression expression = new ExpressionBuilder(input).build();
double result = expression.evaluate();
/*->Write all your code for printing the answer here<-*/
/*for eg:- result.setText(String.valueOf(twoDForm.format(result)))*/
toCalculate = false;
} catch (Exception e) {
stateError = true;
isNumber = false;
}
} else {
/*->Write all your code for clearing the answer here<-*/
/*for eg:- result.setText("")*/
toCalculate = true;
}
}
Or you can do something like this and you don't have to change the function like we did above:-
R.id.Equal: if(toCalculate)
{
calculate();
toCalculate = false;
}else
{
/*->Write all your code for clearing the answer here<-*/
/*for eg:- result.setText("")*/
toCalculate = true;
}
break;

Can this loop code be simplified somehow?

I have a problem... it's basically that my code is ugly and I don't like it. I was wondering if there was a way to simplify it (I use java 8)
I have these "code blocks" that follow this pattern, I have about 5 or 6 of them within a method so this method looks very repetitive and ugly.
The loops are all the same, just the code varies inside.
Is there any way to simplify this?
CODE BLOCK EXAMPLE
String id = null;
for (int i=0; i< NUM_CHECKS; i++) {
// BEGIN VARIABLE CODE
id = getPrice();
if (id != null) break;
// END VARIABLE CODE
// sleep between checks
if (i < NUM_CHECKS -1) Thread.sleep(DELAY);
}
EXAMPLE
String id = null;
for (int i=0; i< NUM_CHECKS; i++) {
// BEGIN VARIABLE CODE
id = getPrice();
if (id != null) break;
// END VARIABLE CODE
// sleep between checks
if (i < NUM_CHECKS -1) Thread.sleep(DELAY);
}
for (int i=0; i< NUM_CHECKS; i++) {
// BEGIN VARIABLE CODE
x=x*2;
if (x>25) break;
// END VARIABLE CODE
// sleep between checks
if (i < NUM_CHECKS -1) Thread.sleep(DELAY);
} etc... a couple more blocks
How about coding an abstraction to contain all the boilerplate?
class MyLoop
{
private int numChecks;
private int delay;
public MyLoop(int numChecks, int delay) {...}
public void loopAndSleep(MyTask task)
throws InterruptedException
{
// Update: It is important to set properly the order of the looping conditions,
// to stop invoking hasEnded() as soon as i<numChecks==false (Thaks to Simon Eismann).
for (int i=0; i<numChecks && !task.hasEnded(); i++)
{
if (i < numChecks -1)
{
Thread.sleep(DELAY);
}
}
}
}
interface MyTask
{
public boolean hasEnded();
}
So, you can replace each one of your 5-6 places in your program by:
new MyLoop(NUM_CHECKS, DELAY).loopAndSleep(new MyTask(){...});
By properly extending MyTask you can give them specific status variables.
If you want to try some operation until the return value is available, you may do the following (Java-8 way):
public static <T> Optional<T> retryWithDelay(int numberOfChecks, int delay,
Supplier<Optional<T>> supplier) throws InterruptedException {
for(int i=0; i<numberOfChecks; i++) {
if(i > 0)
Thread.sleep(DELAY);
Optional<T> result = supplier.get();
if(result.isPresent()) return result;
}
}
And use it like this:
String id = retryWithDelay(NUM_CHECKS, DELAY, () -> Optional.ofNullable(getPrice()))
.orElse(null);
Or if you don't like optionals for some reason, you can stick with null:
public static <T> T retryWithDelay(int numberOfChecks, int delay,
Supplier<T> supplier) throws InterruptedException {
for (int i = 0; i < numberOfChecks; i++) {
if (i > 0)
Thread.sleep(delay);
T result = supplier.get();
if (result != null)
return result;
}
return null;
}
And use it like this:
String id = retryWithDelay(NUM_CHECKS, DELAY, () -> getPrice());
Or using method reference:
String id = retryWithDelay(NUM_CHECKS, DELAY, this::getPrice);
Note that the second example with x = 2*x is more difficult as it has some mutable state. It can be solved in dirty way like this:
AtomicInteger x = new AtomicInteger(1);
Integer result = retryWithDelay(NUM_CHECKS, DELAY, () -> {
int val = x.get()*2;
x.set(val);
return val > 25 ? val : null;
});
However I hope this version was just for illustration, not the real code.
There's also somewhat more sophisticated approach which probably abuses the API, but allows more flexibility. You can create an IntStream of increasing numbers, but they are available with given delay:
public static IntStream delayedStream(int numberOfChecks, int delay) {
return IntStream.range(0, numberOfChecks)
.peek(x -> {
if(x > 0) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
// ignore
}
}
});
}
So the first problem can be solved now as:
String id = delayedStream(NUM_CHECKS, DELAY)
.mapToObj(x -> getPrice())
.filter(Objects::nonNull)
.findFirst().orElse(null);
And the second can be solved like this (assuming initial x value is 1):
int x = delayedStream(NUM_CHECKS, DELAY)
.map(idx -> 1 << (idx+1))
.filter(val -> val > 25)
.findFirst().orElse(-1);
The structure you provide is called a "polling loop" and you are correct, it is poor programming style, as are all the replies that contain the same polling loop.
It would be far better to use events.
Look in the "getPrice()" function, get to wherever that return value is being changed, and create an event when the change happens. Then in your code write a handler and in the handler do all the stuff that currently happens after your polling loop succeeds.
You can use recursion to make to loop reusable, but this would only make sense if you use the loop a lot.
public void loopWithDelay(int numberOfChecks, int delay, Runnable r) {
if (numberOfChecks != 0) {
r.run();
loopWithDelay(numberOfChecks - 1, delay, r);
Thread.sleep(DELAY);
}
}
The actual call would look something like this:
loopWithDelay(5, 1000, new Runnable() {
#Override
public void run() {
//Variable code goes here
}
});
On a general note, are you sure you want to wait DELAY seconds after an action or have the action occur every DELAY seconds?
EDIT:
I am dumb, no need for recursion, this works aswell:
public void loopWithDelay(int numberOfChecks, int delay, Runnable r) {
for (int i = 0; i < numberOfChecks; i++) {
r.run();
if (i != numberOfChecks -1)
Thread.sleep(DELAY);
}
}

understanding with decompiled java code

This is my first time experience of decompiling an apk to java code. The following code is of a local TVApp launcher which is ofcourse android based. To my surprise, I found out that the decompilers do not do a complete conversion to the source code. Hence, it messes up a thing or two. I have tried to work around with what I had, and made functions out of labels. Although I got it to work, but I suppose I missed out on some things..
Can someone guide me how to get this to work correctly? Do I have to do a manual refactoring of the code or is there a tool available for this?
public void run()
{
EN_INPUT_SOURCE_TYPE localEN_INPUT_SOURCE_TYPE;
int i;
ITvServiceServer localITvServiceServer;
for (;;)
{
if (LauncherActivity.this.bExitThread.booleanValue()) {
return;
}
synchronized (LauncherActivity.this.bSync)
{
localEN_INPUT_SOURCE_TYPE = LauncherActivity.this.toChangeInputSource;
LauncherActivity.this.toChangeInputSource = EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_NONE;
i = LauncherActivity.this.fullScale;
LauncherActivity.this.fullScale = 0;
if (localEN_INPUT_SOURCE_TYPE != EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_NONE)
{
localITvServiceServer = ITvServiceServer.Stub.asInterface(ServiceManager.checkService("tv_services"));
if (localITvServiceServer == null) {
Log.w("LauncherActivity", "Unable to find ITvService interface.");
}
}
else
{
if (i != 2) {
break label345;
}
LauncherActivity.this.setPipscale();
try
{
label104:
Thread.sleep(100L);
}
catch (InterruptedException localInterruptedException)
{
localInterruptedException.printStackTrace();
}
}
}
}
for (;;)
{
for (;;)
{
ITvServiceServerCommon localITvServiceServerCommon;
try
{
localITvServiceServerCommon = localITvServiceServer.getCommonManager();
if (localEN_INPUT_SOURCE_TYPE != EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_ATV) {
break label324;
}
if (!localITvServiceServerCommon.GetCurrentInputSource().equals(EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_STORAGE)) {
break;
}
if (LauncherActivity.this.minidatabase != null) {
break label275;
}
j = 0;
if ((j < 0) || (j > EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_NONE.ordinal())) {
break;
}
localITvServiceServerCommon.SetInputSource(EN_INPUT_SOURCE_TYPE.values()[j]);
if (EN_INPUT_SOURCE_TYPE.values()[j] != EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_ATV) {
break label290;
}
k = localITvServiceServer.getChannelManager().getCurrentChannelNumber();
if ((k < 0) || (k > 255)) {
break label361;
}
localITvServiceServer.getChannelManager().programSel(k, EN_MEMBER_SERVICE_TYPE.E_SERVICETYPE_ATV);
}
catch (RemoteException localRemoteException1)
{
localRemoteException1.printStackTrace();
}
break;
label275:
int j = LauncherActivity.this.minidatabase.queryCurInputSrc();
continue;
label290:
if (EN_INPUT_SOURCE_TYPE.values()[j] != EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_DTV) {
break;
}
localITvServiceServer.getChannelManager().changeToFirstService(EN_FIRST_SERVICE_INPUT_TYPE.E_FIRST_SERVICE_DTV, EN_FIRST_SERVICE_TYPE.E_DEFAULT);
break;
try
{
label324:
localITvServiceServerCommon.SetInputSource(localEN_INPUT_SOURCE_TYPE);
}
catch (RemoteException localRemoteException2)
{
localRemoteException2.printStackTrace();
}
}
break;
label345:
if (i != 1) {
break label104;
}
LauncherActivity.this.setFullscale();
break label104;
label361:
int k = 0;
}
}
Do I have to do a manual refactoring of the code? YES.
The only thing you can do (in Eclipse) is pressing ALT+R on a selected label and change all its occurrences.
Decompiling is not 100% complete/accurate, due to how the process works, I suggest you read: http://en.wikipedia.org/wiki/Decompiler to understand more on the process.
It is fairly accurate though on some virtual machines like Java, as its bytecode includes extensive metadata. That's why you got a 'nice' result.
You will have to do a lot of manual refactoring anyway.
And bear in mind the legality of what you are doing, check licenses and copyright.

Categories