So I don't want to avoid an IndexOutofBounds error; however, I want to know how to know when one hits it without crashing the program.
List<String> pool = new ArrayList<>();
pool.add("a");
boolean checked = (pool.get(1) == null); //I know this doensn't work
System.out.println(checked); //I want false
So in this example it is obvious that nothing exists in index 1 of my List pool. Is it possible to get a boolean value for this? Or is it possible to check if the end of a list has been reached without doing i < list.size()? Thanks for your time and help.
It's called a try-catch block:
boolean hasValue;
try {
hasValue = (pool.get(i) != null);
} catch (IndexOutOfBoundsException e) {
hasValue = false;
}
// hasValue == true if non-null value found at index i
However this is an anti-pattern called "exceptions as flow control".
The answer is no. You can check the docs and see that other than checking the size there is no way to "fetch if exists" or to find if "does index exist".
Trying to access the index and catching the exception is possible but not recommended because catching exceptions is an expensive operation in java
Related
I am currently facing an issue with my code and I can't figure out why this statement is evaluating as it is. This is the first time I am using a finally block, so it may be that there is some fundamental behaviour I haven't understood.
What this method does is it gets a json document from an api and stores said document as this.thisPage. Then another method sliceItem does the splitting of the results field into an array of json objects.
A MalformedJsonException is thrown whenever the API returns a json that has bad fields (ex. String fields being stored as int, or int as double etc.). This is tried 10 times (handled by failsafeget) and if it failed 10 times, MalformedJsonException (RuntimeException) is thrown. What I would like slicePage to do in that case is get the next page instead of continuing with this page. To simplify this - each page has 100 entries; if the offset 3500 is broken, we want to get offset 3600.
The issue that I am facing currently is that resp always evaluates to null in the final block. I cannot understand why this is the case, since the try block can return something other than null (JSONObject type).
Any help would be greatly appreciated and if you need more information/code, I am willing to provide it.
public synchronized void slicePage(){
JSONObject resp=null; // otherwise java complains that not initialised
ApiClient apiClient = new ApiClient();
RestEndPoint pageUrl;
while (true) {
pageUrl = getNextPageEndPoint();
if(pageUrl == null) {
throw new IllegalStateException("We have reached the end and the code isn't designed to handle the end here"); // we have reached the end
}
currentPageNumber++;
try {
resp = apiClient.failSafeGet(pageUrl, getRetryCount());
break;
}
catch (MalformedJsonException e) {
logger.info(String.format("The json was still broken after %d retries. Skipping this page and notifying listeners", getRetryCount()));
for (Consumer<Integer> consumer: onSkipListenerList) {
consumer.accept(batchSize); // inform each listener that we are skipping this many entries
}
}
finally { // We need to set the next page end point no matter the outcome of the try catch. N.B. this gets executed even if there is a break
if(resp == null) {
// no next possible
setNextPageEndPoint(null); // don't consider next; we reached the max
this.thisPage = null;
} else {
if(currentPageNumber > maxPages - 1) {
// because a request has been made already, so reduce by 1
setNextPageEndPoint(null); // don't consider next; we reached the max
} else {
// else consider next page
setNextPageEndPoint(constructNextPageEndPoint(pageUrl, resp));
}
this.thisPage = this.parseResult(resp);
setTotalCount(resp.getInt("totalResults"));
}
}
}
}
EDIT I forgot to mention, that when I said it always evaluates to null, I meant that my IDE - Intellij IDEA, is warning me that the if condition always evaluates to null. The following is the help that shows up in Intellij (with Ctrl-F1).
Condition 'resp == null' is always 'true' less... (Ctrl+F1)
This inspection analyzes method control and data flow to report possible conditions that are always true or false, expressions whose value is statically proven to be constant, and situations that can lead to nullability contract violations.
Variables, method parameters and return values marked as #Nullable or #NotNull are treated as nullable (or not-null, respectively) and used during the analysis to check nullability contracts, e.g. report possible NullPointerException errors.
More complex contracts can be defined using #Contract annotation, for example:
#Contract("_, null -> null") — method returns null if its second argument is null #Contract("_, null -> null; _, !null -> !null") — method returns null if its second argument is null and not-null otherwise #Contract("true -> fail") — a typical assertFalse method which throws an exception if true is passed to it
The inspection can be configured to use custom #Nullable
#NotNull annotations (by default the ones from annotations.jar will be used)
EDIT 2
As it turns out, the code analysis is wrong, the value is non-null once run. Thank you everyone (including commentators) for sharing your insights and advice. Ultimately I inserted a logger.info with the value before the condition and everything seemed to work. The reason it seemed to stop working is because the graph server was running into timeouts.
This is normal behaviour. This call
apiClient.failSafeGet(pageUrl, getRetryCount());
throws the exception, so the value assignment to resp is never completed so in the finally block the value is null. So, either you method is always throwing an exception, or, if not, it is returning null at some point.
In your code:
try {
resp = apiClient.failSafeGet(pageUrl, getRetryCount());
break;
}
catch (MalformedJsonException e) {
logger.info(String.format("The json was still broken after %d retries. Skipping this page and notifying listeners", getRetryCount()));
for (Consumer<Integer> consumer: onSkipListenerList) {
consumer.accept(batchSize); // inform each listener that we are skipping this many entries
}
}
finally {.....
If resp = apiClient.failSafeGet(pageUrl, getRetryCount()); throws an exception, resp will be always null, because the program failed before assing the instance to resp.
Okay, I have never had this problem before so I am not sure how to word it or to repair it, I am building a java application that creates dealers, in that application I have the parameters passed in to the DealerFactory.createDealer method and proceed to first check if that dealer exists with a conditional statement that looks like this:
if (DealerFactory.fetchDealer(loginId).getLoginId().equals(loginId)) {
throw new Exception("Sorry That Dealer Already Exists");
} else if (DealerFactory.fetchDealer(loginId).getId().equals(DNo)){
throw new Exception("Sorry That Dealer Already Exists");
} else {
<< proceed with the rest of the method here >>
I have seen this done before so as to check the availability of the username and the id of the person being created. However after running it I found that if I create the dealer and the condition evaluates to true the if statement works just fine letting me know that I have created a user that already exists and I need to create him/her with new a different Id and username. However if the condition evaluates to false I never seem to make it into the else portion of the statement, I am getting no errors, no compilation issues, and no exceptions I have written the statement differently to try that, which wasn't really any different it just looked syntactically different:
if (DealerFactory.fetchDealer(loginId).getLoginId().equals(loginId)
|| DealerFactory.fetchDealer(loginId).getId().equals(DNo)) {
throw new Exception("Sorry That Dealer Already Exists");
}
I have included println statements to follow the program through its run and when the condition evaluates to false I never make it into the else statement. I cant seem to figure out why it is breaking on the condition statement when it is evaluated to false, any thoughts?
edit:::
Ok so that I can be of more assistance in helping you guys help me lol here is the method in its entirety, I apologize for not posting it in the first place
public static int create(String DNo, String name, String admin,
String loginId, String password, String callSrc, String voiSys,
String whoCall, String callBrt, String active, String adfEmail)
throws SQLException, Exception {
int validateResult = 0;
if (DealerFactory.fetchDealer(loginId).getLoginId().equals(loginId)
|| DealerFactory.fetchDealer(loginId).getId().equals(DNo)) {
throw new Exception("Sorry That Dealer Already Exists");
}
try {
DealerFactory.pool = DBConnector.getInstance();
DealerFactory.connect = DBConnector.getConnection();
DealerFactory.preparedStatement = connect
.prepareStatement("Insert Into Dealers (DNo, Dealer, Admin, Login, Password, CallSrc, VoiSys, WhoC, CBrt, Active, ADFemail) "
+ "values(?,?,?,?,?,?,?,?,?,?,?)");
DealerFactory.preparedStatement.setString(1, DNo);
DealerFactory.preparedStatement.setString(2, name);
DealerFactory.preparedStatement.setString(3, admin);
DealerFactory.preparedStatement.setString(4, loginId);
DealerFactory.preparedStatement.setString(5, password);
DealerFactory.preparedStatement.setString(6, callSrc);
DealerFactory.preparedStatement.setString(7, voiSys);
DealerFactory.preparedStatement.setString(8, whoCall);
DealerFactory.preparedStatement.setString(9, callBrt);
DealerFactory.preparedStatement.setString(10, active);
DealerFactory.preparedStatement.setString(11, adfEmail);
validateResult = DealerFactory.preparedStatement
.executeUpdate();
} catch (SQLException ex) {
System.err.println("Error: " + ex + "\n");
ex.printStackTrace();
} finally {
DBUtils.closePrepStatement(DealerFactory.preparedStatement);
DealerFactory.pool.freeConnection(DealerFactory.connect);
}
return validateResult;
}
First things first, you shouldn't chain methods like that due to dangers of NullPointerException
So this part:
if(DealerFactory.fetchDealer(loginId).getLoginId().equals(loginId))
Could look something like this:
if(DealerFactory.fetchDealer(loginId) != null &&
DealerFactory.fetchDealer(loginId).getLoginId().equals(loginId))
Or you could have a separate null check before all your if statements.
However, what you are doing is an overkill. This whole part:
DealerFactory.fetchDealer(loginId).getLoginId()
Returns null if you cannot find a dealer or loginId that you already have.
Assuming your fetchDealer() method returns null if dealer cannot be found.
Instead of:
if(DealerFactory.fetchDealer(loginId).getLoginId().equals(loginId)))
You can just do:
if(DealerFactory.fetchDealer(loginId) != null)
Another improvement you could do is to add a method to DealerFactory called dealerExists(String id) declared something like this:
boolean dealerExists(String id) {
return (YOUR_DATA_STRUCTURE_OF_DEALERS.get(id) != null);
}
Or even:
boolean dealerExists(String id) {
return (fetchDealer(loginId) != null);
}
This would allow for better logical flow of your code. Your if statement would be very clear then:
if(DealerFactory.dealerExists(loginId) {
throw new Exception("Sorry That Dealer Already Exists");
}
Also, the value DNo is the dealer number I presume and you are checking if a dealer exists with the provided loginId or the provided DNo. However, in you checks you are comparing the DNo to the loginId to check if a dealer exists. What exactly is the point of DNo and shouldn't the loginId be enough to determine that the dealer exists?
If you really need to check the DNo as well, just add it as a check within the methods I suggested above.
More information regrading the variables that you are passing into the conditional would be of great help, (i.e. loginId and DNo). The first thing I would do is simplify your conditions in the if & else if statements.
It seems like you could change the if conditional to be if(DealerFactory.fetchDealer(loginId)) and have it work just the same since if the factory returns a dealer with the ID that you are looking for, that dealer already exists. From my understanding of what you're trying to achieve, it's unnecessary to dig any deeper. Also try running through this section of code with the debugger and monitor variables step-by-step to see what things look like at each line of code.
Edit:
You could also move the expressions outside of the conditional and set them to variables. For example:
int dealerId = DealerFactory.fetchDealer(loginId);
if(dealerId != null && dealerId != loginId) {
//<< proceed with the rest of the method here >>
} else {
//<<throw exception>>
}
Checking to see if dealerId is null in the conditional would avoid NullPointerExceptions, and declaring things outside of the conditional will make it easier to debug by hand.
I've been struggling to find why my if statement didnt work properly so I used a try catch block instead. This is the if statement as I had it:
//selectArtistByName returns an Artist object
if (!selectArtistByName(artist.getName()).equals(artist.getName()) ||
selectArtistByName(artist.getName())==null) {
//save data to database
}
When I ran the above, I got a NullPointerException because the method selectArtistByName was returning null as the database was empty. What I don't understand is why it didn't go in the if statement when I was getting null. So I did this and it worked:
try {
if (!selectArtistByName(artist.getName()).equals(artist.getName())) {
}
} catch (NullPointerException e) {
m_db.insert(TABLE_ARTIST, null, artistContents);
}
I'm not a Java guru but it looks like a horrible fix to me. How could I fix this.
You just need to change the order of condition in if block:
if (selectArtistByName(artist.getName()) == null ||
!selectArtistByName(artist.getName()).equals(artist.getName())) {
//save data to database
}
Do the null check first.
If that succeeds, then 2nd condition is not evaluated, and hence no NullPointerException. This is how short-circuit OR operator works. It only evaluates the 2nd expression, if 1st one evaluates to false.
If null check fails, then 2nd condition is evaluated, which wouldn't throw NPE, as it has already been confirmed by first condition.
Also, as rightly pointed out by #ruakh in comment, your condition seems to be broken. selectArtistByName sounds to be returning an Artist, which you can't compare with String.
I guess, you don't even need the 2nd condition. I would assume, selectArtistByName() method has already done the equality check for name, based on which it will return Artist. Just check that selectArtistByName method return null, that would be enough. So, you should change the if block to:
if (selectArtistByName(artist.getName()) == null) {
//save data to database
}
Just put the null condition check at the beginning to shortcut when artist is unknown:
if (selectArtistByName(artist.getName())==null || !selectArtistByName(artist.getName()).equals(artist.getName())) {
//save data to database
}
You can find more info about lazy evaluation in this other question: Does Java have lazy evaluation?
I have created a method that uses an iterator that iterates through a map and for each pair it evaluates a statement with many OR conditions. If the condition is true, it adds the object of the pair (a Notification object) in a list (anomalies). However, at compilation time, the compiler gives a NullPointerException exception at this method. Based on my investigation, it seems that there is a problem in the if statement, but I can't see why. Can anyone give me an help in this? Thanks!
public List<Notification> getAnomalies(NotificationSearchCriteria notificationSearchCriteria) {
Map<String,Notification> messageList = new HashMap<String,Notification>();
List<Notification> anomalies = new ArrayList<Notification>();
Iterator iterator = messageList.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry pairs = (Map.Entry)iterator.next();
Notification message = (Notification) pairs.getValue();
if(message.getDescription().equals(notificationSearchCriteria.getDescription())||message.getSubjectName().equals(notificationSearchCriteria.getSubjectName())||message.getNotificationSubject().toString().equals(notificationSearchCriteria.getNotificationSubject().toString())||message.getNotificationType().toString().equals(notificationSearchCriteria.getNotificationType().toString())){
anomalies.add(message);
}
}
}
return anomalies;
}
This is most likely caused by one of the methods on message returning null. For example, if message.getDescription() returns null, then message.getDescription().equals(<something>) will throw a NullPointerException, since you can't call additional methods on a null object.
There are several ways to fix this. First off, I recommend inspecting your objects to see which can return a null value and add the appropriate handling code.
More generally, I always recommend calling equals on the variable you know not to be null to avoid these problems. For example
if ("accept".equals(command)) {
// do something
}
is generally better than
if (command.equals("accept")) {
// do something
}
because the second might through an NPE, while the first never will.
I would refactor the message-matching code into the NotificationSearchCriteria class. The if would end up being "if (notificationSearchCriteria.matches(message))". From the names, I am guessing that is NotificationSearchCriteria's only usage; in that sense, it would not increase coupling.
The check-for-null would be performed during NotificationSearchCriteria construction; which would ensure that all fields were non-null. In the matching code, within that class, things would look like:
boolean matches(Notification message) {
if (description.equals(message.getDescription()) || // LHS guaranteed non-null
foo.equals(message.getFoo()) ||
bar.equals(message.getBar()) || // ...
) { return true; }
}
The best way to code is to do null check.
Ideally I would have code like this :
while (iterator.hasNext()) {
Map.Entry pairs = (Map.Entry)iterator.next();
Notification message = (Notification) pairs.getValue();
if(null!=message && null!=message.getDescription() &&
null!=notificationSearchCriteria.getDescription() )
{
//Do your comparioson
}else{
//Handle the NullPointerException error the way you want
}
}
I'm refactoring a very large method with a lot of repetition in it.
In the method there are many while loops which include:
if ( count > maxResults){
// Send error response
sendResponse(XMLHelper.buildErrorXMLString("Too many results found, Please refine your search"), out, session);
break;
I want to extract this as a method, because it happens 3 times in this one method currently, but when I do so I get an error on the break as it is no longer within a loop. The problem is that it is still necessary to break out of the while loops, but only when the maximum number of results are reached.
Any suggestions?
Suppose the method is :
public boolean test(int count, int maXResult) {
if ( count > maxResults) {
// Send error response
sendResponse(XMLHelper.buildErrorXMLString("Too many results found, Please refine your search"), out, session);
return true;
}
return false;
}
Call method from loop as :
while(testCondition) {
if (test(count, maxResults)) {
break;
}
}
This is impossible to do directly.
Most often you want to break because you have found the solution and no longer have to search. So indicate in the called function that there is/was success, for instance by returning a result or a boolean to indicate success. And if the function returns success, then break.
If it is now within a method instead of the while loop have it return a value and then break based on that.
i.e.
public bool refactoredMethod(parameters)
{
if ( count > maxResults){
// Send error response
sendResponse(XMLHelper.buildErrorXMLString("Too many results found, Please refine your search"), out, session);
return true;
}
return false;
}
Try to break the loop in the method using return;
As Thriler says you cant do it directly. You could extract part of it to the method and do something like:
if(isTooManyResults(count)) { break; }
Obviously your isTooManyResults method would need to return true if there are too many results and false otherwise