I need to see the result as a boolean result: true. But there's a catch I need to do it in a non-ordinary way.
import java.io.IOException;
public class FlashLight {
private Bulb bulb;
private Battery[] batteries;
public void on() {
try {
if (this.IsThereEnoughPower()) {
this.bulb.setOn(true);
for (Battery b : batteries) {
b.setPower(b.getPower() - this.bulb.getBrightness());
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
this.setBatteries(new Battery[4]);
}
}
I need to catch the exception in method on() but i can only modify method: DetermineIfFlashlightCanBeTurnedOn
public boolean DetermineIfFlashlightCanBeTurnedOn() throws IOException {
return bulb != null && DetermineIfBatteriesAreInstalled() && IsThereEnoughPower();
}
private boolean DetermineIfBatteriesAreInstalled() throws IOException {
if (batteries.length < 4) {
throw new IOException(Math.abs(-4 + batteries.length));
}
for (Battery b : batteries) {
if (b == null) {
return false;
}
}
return true;
}
private boolean IsThereEnoughPower() {
for (Battery b : batteries) {
if (b.getPower() < MIN_BATTERY_POWER) {
return false;
}
}
return true;
}
private static void testLatarki(String... args) {
FlashLight flashlight = new Flashlight();
System.out.println(flashlight.DetermineIfFlashlightCanBeTurnedOn());
}
}
Exception can be caught only in on() method.
DetermineIfBatteriesAreInstalled() DetermineIfFlashlightCanBeTurnedOn
must be signed as: throws IOException.
You can use try{}catch(){} instead :
public boolean DetermineIfFlashlightCanBeTurnedOn() {
try {
return bulb != null && DetermineIfBatteriesAreInstalled() && IsThereEnoughPower();
} catch (Exception e) {
//log your exception
}
return false;
}
I forgot to tell you guys i can use try/catch blocks only in on()
method
In this case you can use RuntimeException you don't need to use throws IOException in your method:
if (batteries.length < 4) {
throw new RuntimeException(Math.abs(-4 + batteries.length)+"");
}
So :
public boolean DetermineIfFlashlightCanBeTurnedOn() {
//--not need to use throw throws IOException-------^
return bulb != null && DetermineIfBatteriesAreInstalled() && IsThereEnoughPower();
}
private boolean DetermineIfBatteriesAreInstalled() {
//--not need to use throw throws IOException------^
if (batteries.length < 4) {
throw new RuntimeException(Math.abs(-4 + batteries.length) + "");
//----------^^
}
for (Battery b : batteries) {
if (b == null) {
return false;
}
}
return true;
}
You can read more here Is there a way to throw an exception without adding the throws declaration?
Related
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()}));
}
The fact is that I need to simultaneously pull in data from the local database, from the server, while checking the connection to the Internet.
Without checking the internet is easy. But when I turn off mobile data, crashes.
I do not understand how to combine and decided to do this:
private void getCategories() {
composite.add(getDataFromLocal(context)
.observeOn(AndroidSchedulers.mainThread()).flatMap(new Function<PromoFilterResponse, ObservableSource<List<FilterCategory>>>() {
#Override
public ObservableSource<List<FilterCategory>> apply(PromoFilterResponse promoFilterResponse) throws Exception {
if (promoFilterResponse != null) {
PreferencesHelper.putObject(context, PreferencesKey.FILTER_CATEGORIES_KEY, promoFilterResponse);
return combineDuplicatedCategories(promoFilterResponse);
} else {
return Observable.empty();
}
}
})
.subscribe(new Consumer<List<FilterCategory>>() {
#Override
public void accept(List<FilterCategory> categories) throws Exception {
if (mView != null) {
mView.hideConnectingProgress();
if (categories != null && categories.size() > 0) {
mView.onCategoriesReceived(categories);
}
}
}
}));
composite.add(InternetUtil.isConnectionAvailable().subscribe(isOnline -> {
if (isOnline) {
composite.add(
getDataFromServer(context)
.flatMap(new Function<PromoFilterResponse, ObservableSource<List<FilterCategory>>>() {
#Override
public ObservableSource<List<FilterCategory>> apply(PromoFilterResponse promoFilterResponse) throws Exception {
if (promoFilterResponse != null) {
PreferencesHelper.putObject(context, PreferencesKey.FILTER_CATEGORIES_KEY, promoFilterResponse);
return combineDuplicatedCategories(promoFilterResponse);
} else {
return Observable.empty();
}
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(categories -> {
if (mView != null) {
mView.hideConnectingProgress();
if (categories != null && categories.size() > 0) {
mView.onCategoriesReceived(categories);
} else {
mView.onCategoriesReceivingFailure(errorMessage[0]);
}
}
}, throwable -> {
if (mView != null) {
if (throwable instanceof HttpException) {
ResponseBody body = ((HttpException) throwable).response().errorBody();
if (body != null) {
errorMessage[0] = body.string();
}
}
mView.hideConnectingProgress();
mView.onCategoriesReceivingFailure(errorMessage[0]);
}
}));
} else {
mView.hideConnectingProgress();
mView.showOfflineMessage();
}
}));
}
private Single<Boolean> checkNetwork(Context context) {
return InternetUtil.isConnectionAvailable()
.subscribeOn(Schedulers.io())
.doOnSuccess(new Consumer<Boolean>() {
#Override
public void accept(Boolean aBoolean) throws Exception {
getDataFromServer(context);
}
});
}
private Observable<PromoFilterResponse> getDataFromServer(Context context) {
return RetrofitHelper.getApiService()
.getFilterCategories(Constants.PROMO_FILTER_CATEGORIES_URL)
.subscribeOn(Schedulers.io())
.retryWhen(BaseDataManager.isAuthException())
.publish(networkResponse -> Observable.merge(networkResponse, getDataFromLocal(context).takeUntil(networkResponse)))
.doOnNext(new Consumer<PromoFilterResponse>() {
#Override
public void accept(PromoFilterResponse promoFilterResponse) throws Exception {
PreferencesHelper.putObject(context, PreferencesKey.FILTER_CATEGORIES_KEY, promoFilterResponse);
}
})
.doOnError(new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
LogUtil.e("ERROR", throwable.getMessage());
}
});
}
private Observable<PromoFilterResponse> getDataFromLocal(Context context) {
PromoFilterResponse response = PreferencesHelper.getObject(context, PreferencesKey.FILTER_CATEGORIES_KEY, PromoFilterResponse.class);
if (response != null) {
return Observable.just(response)
.subscribeOn(Schedulers.io());
} else {
return Observable.empty();
}
}
As you can see, connect the local database separately, simultaneously check the Internet and upload data from the server.
But it seems to me not quite right. Moreover, the subscriber is duplicated and so on.
I saw a lot of tutorials, where the combination of the local database with the API is described, but I did not see it at the same time processing the connection error with the Internet.
I think many people faced such a problem and how did you solve it?
Suppose You have two Obsevable: one from server and another from database
You can merge them into one stream like below:
public Observable<Joke> getAllJokes() {
Observable<Joke> remote = mRepository.getAllJokes()
.subscribeOn(Schedulers.io());
Observable<Joke> local = mRepository.getAllJokes().subscribeOn(Schedulers.io());
return Observable.mergeDelayError(local, remote).filter(joke -> joke != null);
}
Im' not android developer, but in my mind methods return types should be something like this:
//just for demonstration
static boolean isOnline = false;
static class NoInternet extends RuntimeException {
}
private static Completable ensureOnline() {
if (isOnline)
return Completable.complete();
else
return Completable.error(new NoInternet());
}
private static Single<String> getDataFromServer() {
return Single.just("From server");
}
private static Maybe<String> getDataFromLocal() {
return Maybe.just("From local");//or Maybe.never()
}
We can run all in parallel with Observable.merge. But what if error NoIternet happens? Merged observable will fail. We can use materialisation - transform all emission and errors to onNext value.
private static void loadData() {
Observable<Notification<String>> fromServer = ensureOnline().andThen(getDataFromServer()).toObservable().materialize();
Observable<Notification<String>> fromLocaldb = getDataFromLocal().toObservable().materialize();
Observable.merge(fromLocaldb, fromServer)
.subscribe(notification -> {
if (notification.isOnNext()) {
//calls one or two times(db+server || db || server)
//show data in ui
} else if (notification.isOnError()) {
if (notification.getError() instanceof NoInternet) {
//show no internet
} else {
//show another error
}
} else if (notification.isOnComplete()){
//hide progress bar
}
});
}
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
I have a method which tries to get the current message in an arraylist of mesages and if there are none then it returns null, however I get an index out of bounds exception and I can't understand why
public Message getCurrent() {
if(this.size() <= 0) {
return null;
}else {
return this.get(currentMessageIndex);
}
}
The following calls the above method in another class and throws the exception:
public void run() {
while (running) {
//Message msg = clientQueue.getLast(); // Matches EEEEE in ServerReceiver
Message msg = clientQueue.getCurrent();
System.out.flush();
if (msg != null) {
if (msg.getSent() == false) {
client.println(msg);// Matches FFFFF in ClientReceiver
client.flush();
msg.setSent();
}
}
}
return;
}
public Message getCurrent() {
if(this.size() <= 0) {
return null;
}else {
return (this.size() > currentMessageIndex) ? this.get(currentMessageIndex) : null;
}}
Can you try with this, I have handled fail over case.
Just use
this.size()-1
Instead of
this.size()
My problem is very usual but i can't seem to find any solution. I have searched a lot but didn't find anything
Situation:
tried to insert a row which caused foreign key violation that caused my transaction to rollback.
No matter what exception i handle it always throws 500 from my rest endpoint which is not acceptable at all
Question:
How to handle this gracefully. Below is my code which is not working
#Transactional(dontRollbackOn={InvalidModelException.class,PersistenceException.class,ConstraintViolationException.class,MySQLIntegrityConstraintViolationException.class})
#Override
public PointAudit createPointAudit(PointAudit pointAudit) throws EmptyModelException, InvalidModelException {
if(pointAudit != null) {
try {
this.entityManager.persist(pointAudit);
this.entityManager.flush();
}
catch(RollbackException x) {
LOGGER.error(x.getMessage(), x);
}
catch(PersistenceException x) {
if(x.getCause() instanceof ConstraintViolationException) {
if(x.getCause().getCause() instanceof MySQLIntegrityConstraintViolationException)
{
MySQLIntegrityConstraintViolationException e = (MySQLIntegrityConstraintViolationException)x.getCause().getCause();
if(e.getMessage().contains("USER_ID")) {
throw new InvalidModelException("Invalid user is provided");
}
else {
if(e.getMessage().contains("STATUS")) {
throw new InvalidModelException("Invalid status is provided");
}
else {
if(e.getMessage().contains("CHANNEL")) {
throw new InvalidModelException("Invalid channel is provided");
}
else {
if(e.getMessage().contains("ACTION")) {
throw new InvalidModelException("Invalid action is provided");
}
}
}
}
}
}
else {
while( !(x.getCause() instanceof RollbackException) || x.getCause() == null) {
LOGGER.error(x.getMessage(), x);
}
}
}
}
else {
throw new EmptyModelException("Point Audit is empty");
}
return pointAudit;
}
If any further code is required please let me know