This question already has answers here:
Try Catch Performance Java
(4 answers)
Closed 3 months ago.
First of all, I want to describe that there are more than five thousand records. Please let me know the best method for best performance from the following:
String hmVALUE = "";
try
{
hmVALUE = hashmapRECORDS.get(key).toString();
}
catch(Exception ex)
{
hmVALUE = "";
}
// Second method:
String hmVALUE = "";
if(Module.hmQUEUED_REQUESTS.containsKey(key))
{
hmVALUE = hashmapRECORDS.get(key).toString();
}
else
{
hmVALUE = "";
}
I am using try-catch and want to know which method is best.
Neither is ideal. Better to call get() and check if the result is null:
String hmVALUE = "";
Object value = hashmapRECORDS.get(key);
if (value != null) {
hmVALUE = value.toString();
}
Generally speaking, exceptions are much heavier operations for Java to generate (they need to collect stack traces, etc...) so in this specific case, I would say that if-statement is much better than try-catch.
However, for the question in general, those are completely different mechanisms - the 1st one should handle an unexpected error, while the other one is flow control.
Moreover, you can use the short condition ? if true : if false syntax and have the entire code like this:
String hmVALUE = Module.hmQUEUED_REQUESTS.containsKey(key) ? hashmapRECORDS.get(key).toString() : ""
And more specifically in your case, you can just use the getOrDefault() method:
String hmVALUE = hashmapRECORDS.getOrDefault(key, "");
Related
Giving an example, lets say we have a code like the one below:
String phone = currentCustomer.getMainAddress().getContactInformation().getLandline()
As we know there is no elvis operator in Java and catching NPE like this:
String phone = null;
try {
phone = currentCustomer.getMainAddress().getContactInformation().getLandline()
} catch (NullPointerException npe) {}
Is not something anyone would advise. Using Java 8 Optional is one solution but the code is far from clear to read -> something along these lines:
String phone = Optional.ofNullable(currentCustomer).flatMap(Customer::getMainAddress)
.flatMap(Address::getContactInformation)
.map(ContactInfo::getLandline)
.orElse(null);
So, is there any other robust solution that does not sacrifice readability?
Edit: There were some good ideas already below, but let's assume the model is either auto generated (not convenient to alter each time) or inside a third party jar that would need to be rebuild from source to be modified.
The "heart" of the problem
This pattern currentCustomer.getMainAddress().getContactInformation().getLandline() is called TrainWreck and should be avoided. Had you done that - not only you'd have better encapsulation and less coupled code, as a "side-effect" you wouldn't have to deal with this problem you're currently facing.
How to do it?
Simple, the class of currentCustomer should expose a new method: getPhoneNumber() this way the user can call: currentCustomer.getPhoneNumber() without worrying about the implementation details (which are exposed by the train-wreck).
Does it completely solve my problem?
No. But now you can use Java 8 optional to tweak the last step. Unlike the example in the question, Optionals are used to return from a method when the returned value might be null, lets see how it can be implemented (inside class Customer):
Optional<String> getPhoneNumber() {
Optional<String> phone = Optional.empty();
try {
phone = Optional.of(mainAddress.getContactInformation().getLandline());
} catch (NullPointerException npe) {
// you might want to do something here:
// print to log, report error metric etc
}
return phone;
}
Per Nick's comment below, ideally, the method getLandline() would return an Optional<String>, this way we can skip the bad practice of swallowing up exceptions (and also raising them when we can avoid it), this would also make our code cleaner as well as more concise:
Optional<String> getPhoneNumber() {
Optional<String> phone = mainAddress.getContactInformation().getLandline();
return phone;
}
String s = null;
System.out.println(s == null);
or
String s = null;
if(s == null)System.out.println("Bad Input, please try again");
If your question was with the object being null, you should have made that clear in your question...
PhoneObject po = null;
if(po==null) System.out.println("This object is null");
If your problem is with checking whether all the parts of the line are null, then you should have also made that clear...
if(phone == null) return -1;
Customer c = phone.currentCustomer();
if(c == null)return -1;
MainAddress ma = c.getMainAddress();
if(ma == null) return -1;
ContactInfo ci = ma.getContactInformation();
if(ci == null)return -1;
LandLine ll = ci.getLandline();
if(ll == null)return -1;
else return ll.toNumber()//or whatever method
Honestly, code that's well written shouldn't have this many opportunities to return null.
This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 8 years ago.
I just want to know why the compiler allow to continue the program normally in the first condition:
public void ButtonOnClickDirectoryList(View v){
try {
if (!spnOptionSelectedDepartment.equals(null) && !spnOptionSelectedCities.equals(null)) {
if (!spnOptionSelectedTypes.equals(null)) { //code....}
the spnOptionSelectedDepartment and spnOptionSelectedTypes are Strings and are defined at the begining of the class like this:
private String spnOptionSelectedDepartment = null;
private String spnOptionSelectedCities = null;
private String spnOptionSelectedTypes = null;
so when I press the button, it call this method and this are the values that I have in the moment:
spnOptionSelectedDepartment = "9999"
spnOptionSelectedCities = null
spnOptionSelectedTypes = null
so when I put a break point on this condition it just continue validating the rest of the code inside that if...
Could anybody explain me why this behavior?
Let me edit the question, Yes it throws nullpointer exception on the second if...
if (!spnOptionSelectedTypes.equals(null)) {
but why it allows the first IF when spnOptionSelectedCities = null...?
It shouldn't continue, it should throw a NullPointerException that you may intercept in the catch block.
When you try
if (!spnOptionSelectedTypes.equals(null))
it should throw this exception because spnOptionSelectedTypes is null so it is not a String and does not have any equals() method.
Edit:
It allows the first if to pass because it has 2 tests
if (A OR B) {
If A is true, the B condition is not tested because only one is required to continue, because of the OR operator.
Edit 2:
With:
if (A AND B) {
If A is true, B will also be tested and throw a NullPointerException if spnOptionSelectedCities is null.
Definitive answer:
Null tests in Java
if (x != null && y != null) {
x.doSomething();
y.doSomethingElse();
}
I have a ConcurrentHashMap that exhibits strange behavior on occasion.
When my app first starts up, I read a directory from the file system and load contents of each file into the ConcurrentHashMap using the filename as the key. Some files may be empty, in which case I set the value to "empty".
Once all files have been loaded, a pool of worker threads will wait for external requests. When a request comes in, I call the getData() function where I check if the ConcurrentHashMap contains the key. If the key exists I get the value and check if the value is "empty". If value.contains("empty"), I return "file not found". Otherwise, the contents of the file is returned. When the key does not exist, I try to load the file from the file system.
private String getData(String name) {
String reply = null;
if (map.containsKey(name)) {
reply = map.get(name);
} else {
reply = getDataFromFileSystem(name);
}
if (reply != null && !reply.contains("empty")) {
return reply;
}
return "file not found";
}
On occasion, the ConcurrentHashMap will return the contents of a non-empty file (i.e. value.contains("empty") == false), however the line:
if (reply != null && !reply.contains("empty"))
returns FALSE. I broke down the IF statement into two parts: if (reply != null) and if (!reply.contains("empty")). The first part of the IF statement returns TRUE. The second part returns FALSE. So I decided to print out the variable "reply" in order to determine if the contents of the string does in fact contain "empty". This was NOT the case i.e. the contents did not contain the string "empty". Furthermore, I added the line
int indexOf = reply.indexOf("empty");
Since the variable reply did not contain the string "empty" when I printed it out, I was expecting indexOf to return -1. But the function returned a value approx the length of the string i.e. if reply.length == 15100, then reply.indexOf("empty") was returning 15099.
I experience this issue on a weekly basis, approx 2-3 times a week. This process is restarted on a daily basis therefore the ConcurrentHashMap is re-generated regularly.
Has anyone seen such behavior when using Java's ConcurrentHashMap?
EDIT
private String getDataFromFileSystem(String name) {
String contents = "empty";
try {
File folder = new File(dir);
File[] fileList = folder.listFiles();
for (int i = 0; i < fileList.length; i++) {
if (fileList[i].isFile() && fileList[i].getName().contains(name)) {
String fileName = fileList[i].getAbsolutePath();
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(fileName);
br = new BufferedReader(fr);
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null) {
contents += sCurrentLine.trim();
}
if (contents.equals("")) {
contents = "empty";
}
return contents;
} catch (Exception e) {
e.printStackTrace();
if (contents.equals("")) {
contents = "empty";
}
return contents;
} finally {
if (fr != null) {
try {
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (br != null) {
try {
br.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (map.containsKey(name)) {
map.remove(name);
}
map.put(name, contents);
}
}
}
} catch (Exception e) {
e.printStackTrace();
if (contents.equals("")) {
contents = "empty";
}
return contents;
}
return contents;
}
I think your problem is that some of your operations should be atomic and they aren't.
For example, one possible thread interleaving scenario is the following:
Thread 1 reads this line in the getData method:
if (map.containsKey(name)) // (1)
the result is false and Thread 1 goes to
reply = getDataFromFileSystem(name); // (2)
in getDataFromFileSystem, you have the following code:
if (map.containsKey(name)) { // (3)
map.remove(name); // (4)
}
map.put(name, contents); // (5)
imagine that another thread (Thread 2) arrives at (1) while Thread 1 is between (4) and (5): name is not in the map, so thread 2 goes to (2) again
Now that does not explain the specific issue you are observing but it illustrates the fact that when you let many threads run concurrently in a section of code without synchronization, weird things can and do happen.
As it stands, I can't find an explanation for the scenario you describe, unless you call reply = map.get(name) more than once in your tests, in which case it is very possible that the 2 calls don't return the same result.
First off, don't even think that there is a bug in ConcurrentHashMap. JDK faults are very rare and even entertaining the idea will pull you away from properly debugging your code.
I think your bug is as follows. Since you are using contains("empty") what happens if the line from the file has the word "empty" in it? Isn't that going to screw things up?
Instead of using contains("empty") I would use ==. Make the "empty" a private static final String then you can use equality on it.
private final static String EMPTY_STRING_REFERENCE = "empty";
...
if (reply != null && reply != EMPTY_STRING_REFERENCE) {
return reply;
}
...
String contents = EMPTY_STRING_REFERENCE;
...
// really this should be if (contents.isEmpty())
if (contents.equals("")) {
contents = EMPTY_STRING_REFERENCE;
}
This is, btw, the only time you should be using == to compare strings. In this case you want to test it by reference and not by contents since lines from your files could actually contain the magic string.
Here are some other points:
In general, whenever you are using the same String in multiple places in your program, it should be pulled up to a static final field. Java will probably do this for you anyway but it makes the code a lot cleaner as well.
#assylias is spot on about race conditions when you make 2 calls to ConcurrentHashMap. For example, instead of doing:
if (map.containsKey(name)) {
reply = map.get(name);
} else {
You should do the following so you do only one.
reply = map.get(name);
if (reply == null) {
In your code you do this:
if (map.containsKey(name)) {
map.remove(name);
}
map.put(name, contents);
That should be rewritten as the following. There is no need to remove before the put which introduces race conditions as #assylias mentioned.
map.put(name, contents);
You said:
if reply.length == 15100, then reply.indexOf("empty") was returning 15099.
This is not possible with the same reply String. I suspect that you were looking at different threads or in some other way misinterpreting the output. Again, don't be fooled into thinking that there are bugs in java.lang.String.
First, using ConcurrentHashMap does not protect you if you call its methods from multiple threads in sequence. If you call containsKey and get afterwards and another thread calls remove in between you will have a null result. Be sure to call only get and check for null instead of containsKey/get. It's also better regarding performance, because both methods nearly have the same cost.
Second, the weird indexOf call result is either due to a programming error, or points to memory corruption. Is there any native code involved in your application? What are you doing in getDataFromFileSystem? I observed memory corruption when using FileChannel objects from multiple threads.
I have this line code:
String name = Book.getName();
/*next lines of code*/
Next, variable name processing in other code without any checks.
In some cases, possible situation, when name=null and other code will exit with an error.
It is bad.
Also, I cant access to the other code.
So, what do you think, my next implementation is correct:
try
{
String name = Book.getName();
if(null== name)
throw new NullPointerException("method 'getName' return null");
/*next lines of code*/
}
catch(NullPointerException e)
{
System.out.print("Hey! Where book name? I exit!");
System.exit();
}
I have any other choose in this case?
It is possible to generate any other type of Exception or only NullPointerException?
Thanks.
Edit:
Ok,
String name = Book.getName();
it's imagine code line. In real case, I have more complex code:
List<Book> bookList= new ArrayList<Book>();
String name = null;
Iterator i = BookShop.getBooks.iterator(); //BookShop it is input parameter!
while(i.hasNext())
{
Book book = (Book) i.next;
name = book.getName();
nameList.add(name);
}
This example more full.
So, in this code input parameter BookShop Object.
What problem I can have with this Object?
BookShop can be NULL;
method BookShop.getBooks() can return NULL;
Also, getName() can return NULL too.
So, general problem next: there is no guarantee the correctness of input parameter BookShop!
And I must to consider every possible option (3 NULL)
For me, add General try-catch block and that all.
No?
You can create any exception you like by extending the Exception class, like a NoNameProvidedException for example. There are a lot of example one Google to help you do that.
I guess in your case just checking with an if if the name is null should be sufficient as you just want to do a System.exit().
Your code is a bit iffy, but I assume you're learning. You don't need to throw the NullPointerException explicitly, you can throw whatever Exceptions you like.
But you probably don't really need the Exception catching here, you can just check for the null and handle the situation appropriately if it's true.
Also, please avoid Yoda conditions. Your if statement should read
if name is null
so
if (name == null)
I would probably use IllegalStateException:
String name = Book.getName();
if (name == null) {
throw new IllegalStateException
("Method foo must not be called when the book has no name");
}
It really depends on where the state is coming from though - it's not really clear what's going wrong here.
I certainly wouldn't start catching NullPointerException - exceptions like that (and the illegal state one) shouldn't be explicitly caught. Let them bubble up, and if it's appropriate have some sort of top-level handler.
Exceptions should not be used for normal control flow. Just use the if block:
String name = Book.getName();
if (name == null) {
System.out.print("Hey! Where book name? I exit!");
System.exit();
}
/*next lines of code*/
Using try and catch in this case is unneeded. You can just write like this:
if(Book.getName() != null)
String name = Book.getName();
else
//handle the situation with null
You don't need to throw an Exception in this case - just handle the null value and you are fine.
It's more friendly for Java not to use exceptions, but just check the return value
String name = Book.getName();
if (name == null)
System.out.print("Hey! Where book name? I exit!");
else {
/*next lines of code*/
}
Here is a simple code snippet and I cannot figure out why does it throw a NullPointerException.
String lastGroup = "";
menuTevekenysegekGrouped = new ArrayList<MenuElem>();
for(MenuElem me : menuA) {
// double checked that me objects are never null
// double checked that menuA is never null
if(me.getGroup() != null && !me.getGroup().equals(lastGroup)) { /* NPE!!! */
lastGroup = me.getGroup();
MenuElem separ = new MenuElem();
separ.setCaption(lastGroup);
separ.setGroupHead(true);
menuTevekenysegekGrouped.add(separ);
menuTevekenysegekGrouped.add(me);
} else {
menuTevekenysegekGrouped.add(me);
}
}
In the first iteration the me.getGroup() returns null. So the first operand of the && is false and second operand should not evaluate according to the JLS, as far as I know. However when I debug the code I get NPE from the marked line. I'd like to know why. (Using JRockit 1.6.0_05 if it matters..)
Are you sure that me itself is not, in fact, null?
From your code (without the stacktrace I have to guess), the following may be null and be the cause: menuA or me or menuTevekenysegekGrouped. And some of the values returned from the methods/or used in the methods may also be null, but it's hard to know...
If me is not null, then the only other object that can be null in the above snippet is menuTevekenysegekGrouped. Add a check before first using it to ensure that it's not null.
The repeated calls to me.getGroup() would bug me enough to pull them out into a local variable:
String lastGroup = "";
for(MenuElem me : menuA) {
String thisGroup = me.getGroup();
if(thisGroup != null && !thisGroup.equals(lastGroup)) {
lastGroup = thisGroup;
MenuElem separ = new MenuElem();
separ.setCaption(lastGroup);
separ.setGroupHead(true);
menuTevekenysegekGrouped.add(separ);
menuTevekenysegekGrouped.add(me);
} else {
menuTevekenysegekGrouped.add(me);
}
}
This is only going to fix your problem if in fact me.getGroup() returns different values (sometimes null) on multiple calls with the same me, but it might make it easier to debug, and certainly makes it easier to read.