Faced this with a situation - in the main method, a child method is called, which checks the object, and an exception is thrown in this child method (one of the objects in the list NULL). But the code of the main method still continues to be executed!
Example code:
#Transactional
public boolean addCompany(List<Company> companies, List<Address> addresses) throws Exception{
checkAddress(addresses);
try{
for(int i = 0; i < companies.size(); i++){
if(findCompany(companies.get(i).getId()) == null && !isExistsCompany(companies.get(i))){
companies.get(i).setAddress(addresses.get(i));
this.em.persist(companies.get(i));
}
}
}catch(Exception e){
return false;
}
return true;
}
public void checkAddress(List<Address> addresses) throws Exception{
try{
if(addresses == null)
throw new Exception(Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + ": Invalid parameter: list is null");
for(Address a : addresses)
if(a == null)
throw new Exception(Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + ": Invalid list item: object is null");
}catch(Exception e){
e.printStackTrace();
}
}
In this regard, several questions arose:
- why the code does not stop?
- Is it now necessary, as an option, to get out of the situation by changing the type of the checkAddress method from void to boolean, and in the main method to process true/false?
- How is correctly handled on the frontend such error - do the text send exceptions to the frontend or just process the code 500 and if so, then why generate an exception on the backend - to help in the development process? How to deal with it competently?
Advise please.
Thanks in advance.
You are catching the Exception(s), when you do not rethrow a Exception the Java runtime considers it handled. If you expected program execution to stop then you need the Exception(s) to propagate to the caller. For example, in checkAddress change
} catch(Exception e) {
e.printStackTrace();
}
to something like
} catch(Exception e) {
e.printStackTrace();
throw e; // <-- re-throw the Exception
}
or simply remove the try and catch altogether, then the Exception is automatically thrown to the caller. Also, in Java 8+, you could use a Stream. Like,
public void checkAddress(List<Address> addresses) throws Exception {
if (addresses == null) {
StackTraceElement[] ste = Thread.currentThread().getStackTrace();
throw new Exception(ste[2].getClassName() + "."
+ ste[2].getMethodName() + "." + ste[1].getMethodName()
+ ": Invalid parameter: list is null");
}
if (addresses.stream().anyMatch(a -> a == null)) {
StackTraceElement[] ste = Thread.currentThread().getStackTrace();
throw new Exception(ste[2].getClassName() + "."
+ ste[2].getMethodName() + "." + ste[1].getMethodName()
+ ": Invalid list item: object is null");
}
}
You need to remove try.. catch block from inside checkAddress() method. That way, any exception thrown from inside checkAddress() are propagate to its caller.
In addCompany() method, put call to checkAddress() method inside try .. catch and handle the exception there.
When checkAddress() throws exception, code execution will jump to catch block.
e.printStackTrace();
This line suppresses the exception, causing your code to continue rather than fail. It prints the stack trace, which might make it look like the exception is being thrown, but it's not getting any further than that line.
You almost never want to use printStackTrace(), you should instead properly handle the exceptions you intend to, or just let the exception propagate to the callers of your method.
Try this:
public void checkAddress(List<Address> addresses) throws Exception{
if(addresses == null)
throw new Exception(Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + ": Invalid parameter: list is null");
for(Address a : addresses)
if(a == null)
throw new Exception(Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + ": Invalid list item: object is null");
}
}
What is all that stuff about threads? Crazy code.
Don't allow anyone to add a null instance to the List in the first place.
I might write it this way:
public void checkAddresses(List<Address> addresses) {
if (addresses == null) throw new IllegalArgumentException("Address List cannot be null");
for (Address a : addresses) {
if (a == null) throw new IllegalArgumentException("Address cannot be null");
}
}
Related
For code quality reasons, I would like to replace a try catch block inside my code with an if condition in order to avoid using a FrontendException.
Here is my code :
Schema mySchema = new Schema();
mySchema.add(new Schema.FieldSchema("myInteger", DataType.INTEGER));
mySchema.add(new Schema.FieldSchema("myBoolean", DataType.BOOLEAN));
Schema tupleSchema = new Schema();
try {
tupleSchema.add(new Schema.FieldSchema("ARRAY_ELEM", mySchema, DataType.BAG));
} catch (FrontendException e) {
tupleSchema = new Schema(new Schema.FieldSchema(getSchemaName("myClass", input), DataType.DOUBLE));
}
return tupleSchema;
Is it possible to replace this code using an if else condition? This way I won't have to use this type of Exception and that would be better for SonarQube.
Any ideas?
The exception thrown by the Schema.FieldSchema constructor is deterministic. Here is the code of the constructor;
public FieldSchema(String a, Schema s, byte t) throws FrontendException {
alias = a;
schema = s;
log.debug("t: " + t + " Bag: " + DataType.BAG + " tuple: " + DataType.TUPLE);
if ((null != s) && !(DataType.isSchemaType(t))) {
int errCode = 1020;
throw new FrontendException("Only a BAG, TUPLE or MAP can have schemas. Got "
+ DataType.findTypeName(t), errCode, PigException.INPUT);
}
type = t;
canonicalName = CanonicalNamer.getNewName();
}
So the exception is thrown if;
the Schema given is null
the DataType given is not a schema type
You know in advance whether the exception will be thrown. In your case it is not so you can safely ignore the exception as it can never be thrown. You can remove the code in the catch block. You may as well replace it with;
throw new IllegalStateException("Summon Cthulhu");
Its a similar case to getting the UTF-8 charset;
String test = "abc";
byte[] bytes;
try {
bytes = test.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
//Can never happen although the compiler forces us to catch it
}
although the method getBytes can throw an exception if the charset is not supported, the UTF-8 charset is always guaranteed to be supported.
There are a lot of concurrent mod exception questions, but I'm unable to find an answer that has helped me resolve my issue. If you find an answer that does, please supply a link instead of just down voting.
So I originally got a concurrent mod error when attempting to search through an arraylist and remove elements. For a while, I had it resolved by creating a second arraylist, adding the discovered elements to it, then using removeAll() outside the for loop. This seemed to work, but as I used the for loop to import data from multiple files I started getting concurrent modification exceptions again, but intermittently for some reason. Any help would be greatly appreciated.
Here's the specific method having the problem (as well as the other methods it calls...):
public static void removeData(ServiceRequest r) {
readData();
ArrayList<ServiceRequest> targets = new ArrayList<ServiceRequest>();
for (ServiceRequest s : serviceQueue) {
//ConcurrentModification Exception triggered on previous line
if (
s.getClient().getSms() == r.getClient().getSms() &&
s.getTech().getName().equals(r.getTech().getName()) &&
s.getDate().equals(r.getDate())) {
JOptionPane.showMessageDialog(null, s.getClient().getSms() + "'s Service Request with " + s.getTech().getName() + " on " + s.getDate().toString() + " has been removed!");
targets.add(s);
System.out.print("targetted"); }
}
if (targets.isEmpty()) { System.out.print("*"); }
else {
System.out.print("removed");
serviceQueue.removeAll(targets);
writeData(); }
}
public static void addData(ServiceRequest r) {
readData();
removeData(r);
if (r.getClient().getStatus().equals("MEMBER") || r.getClient().getStatus().equals("ALISTER")) {
serviceQueue.add(r); }
else if (r.getClient().getStatus().equals("BANNED") || r.getClient().getStatus().equals("UNKNOWN")) {
JOptionPane.showMessageDialog(null, "New Request failed: " + r.getClient().getSms() + " is " + r.getClient().getStatus() + "!", "ERROR: " + r.getClient().getSms(), JOptionPane.WARNING_MESSAGE);
}
else {
int response = JOptionPane.showConfirmDialog(null, r.getClient().getSms() + " is " + r.getClient().getStatus() + "...", "Manually Overide?", JOptionPane.OK_CANCEL_OPTION);
if (response == JOptionPane.OK_OPTION) {
serviceQueue.add(r); }
}
writeData(); }
public static void readData() {
try {
Boolean complete = false;
FileReader reader = new FileReader(f);
ObjectInputStream in = xstream.createObjectInputStream(reader);
serviceQueue.clear();
while(complete != true) {
ServiceRequest test = (ServiceRequest)in.readObject();
if(test != null && test.getDate().isAfter(LocalDate.now().minusDays(180))) {
serviceQueue.add(test); }
else { complete = true; }
}
in.close(); }
catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }
}
public static void writeData() {
if(serviceQueue.isEmpty()) { serviceQueue.add(new ServiceRequest()); }
try {
FileWriter writer = new FileWriter(f);
ObjectOutputStream out = xstream.createObjectOutputStream(writer);
for(ServiceRequest r : serviceQueue) { out.writeObject(r); }
out.writeObject(null);
out.close(); }
catch (IOException e) { e.printStackTrace(); }
}
EDIT
The changes cause the concurrent mod to trigger every time rather than intermittently, which I guess means the removal code is better but the error now triggers at it.remove();
public static void removeData(ServiceRequest r) {
readData();
for(Iterator<ServiceRequest> it = serviceQueue.iterator(); it.hasNext();) {
ServiceRequest s = it.next();
if (
s.getClient().getSms() == r.getClient().getSms() &&
s.getTech().getName().equals(r.getTech().getName()) &&
s.getDate().equals(r.getDate())) {
JOptionPane.showMessageDialog(null, s.getClient().getSms() + "'s Service Request with " + s.getTech().getName() + " on " + s.getDate().toString() + " has been removed!");
it.remove(); //Triggers here (line 195)
System.out.print("targetted"); }
}
writeData(); }
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificatio
nException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at data.ServiceRequest.removeData(ServiceRequest.java:195)
at data.ServiceRequest.addData(ServiceRequest.java:209) <...>
EDIT
After some more searching, I've switch the for loop to:
Iterator<ServiceRequest> it = serviceQueue.iterator();
while(it.hasNext()) {
and it's back to intermittently triggering. By that I mean the first time I attempt to import data (the removeData method is being triggered from the addData method) it triggers the concurrent mod exception, but the next try it pushes past the failure and moves on to another file. I know there's a lot of these concurrent mod questions, but I'm not finding anything that helps in my situation so links to other answers are more than welcome...
This is not how to do it, to remove elements while going through a List you use an iterator. Like that :
List<ServiceRequest> targets = new ArrayList<ServiceRequest>();
for(Iterator<ServiceRequest> it = targets.iterator(); it.hasNext();) {
ServiceRequest currentServReq = it.next();
if(someCondition) {
it.remove();
}
}
And you will not get ConcurrentModificationException this way if you only have one thread.
If there is multiple threads involved in your code, you may still get ConcurrentModificationException. One way to solve this, is to use Collections.synchronizedCollection(...) on your collection (serviceQueue) and as a result you will get a synchronized collection that will not produce ConcurrentModificationException. But, you code may become very slow.
Im kinda new to handling exceptions in Java with Junit, a little guidence would be much appreciated.
What I am trying to do:
I surround the creation of the new CustomObject with a try as the user can pass in a String that will not match an enum when we call valueof(). I want to be able to catch an exception here, which I am, though I am told: "A catch statement that catches an exception only to rethrow it should be avoided.". There must be a better way to handle this?
If the new object has the correct enum then I call isValidObject, which returns a boolean. If the Integer is not valid then I throw an exception.
My test has a #Test(expected = AssertionError.class) and is passing.
Is there a better/cleaner way to use the exceptions?
I have the code below:
private CustomObject getObjectFromString(String objectDataString) {
if (objectDataString != null) {
String[] customObjectComponents = objectDataString.split(":");
try {
CustomObject singleObject = new CustomObject(EnumObjectType.valueOf(customObjectComponents [0]),
Integer.parseInt(customObjectComponents [1]));
if (isValidCustomObject(singleObject)) {
return singleObject;
} else {
throw new IllegalArgumentException("Unknown custom object type/value: " + EnumObjectType.valueOf(customObjectComponents [0]) + ":"
+ Integer.parseInt(customObjectComponents [1]));
}
} catch (IllegalArgumentException e) {
throw e;
}
}
Oh, and if anyone can recommend anything good to read about exception handling, that would be great.
A catch statement that catches an exception only to rethrow it should be avoided.". There must be a better way to handle this?
Yes, simply remove the try catch. Your code is equivalent to:
private CustomObject getObjectFromString(String objectDataString) {
if (objectDataString != null) {
String[] customObjectComponents = objectDataString.split(":");
CustomObject singleObject = new CustomObject(EnumObjectType.valueOf(customObjectComponents[0]),
Integer.parseInt(customObjectComponents[1]));
if (isValidCustomObject(singleObject)) {
return singleObject;
} else {
throw new IllegalArgumentException("Unknown custom object type/value: " + EnumObjectType.valueOf(customObjectComponents[0]) + ":"
+ Integer.parseInt(customObjectComponents[1]));
}
}
}
That code will throw an IllegalArgumentException if the value passed to your enum.valueOf() is not valid or if your isValidCustomObject method returns false.
Note that it might also throw an IndexOutOfBoundException if the string does not contain a : which you probably want to test before calling customObjectComponents[1]. And it might throw NumberFormatException too.
And you seem to accept a null String as a valid entry, which is probably not a good idea (depends on your use case obviously).
I would probably have written it that way:
private CustomObject getObjectFromString(String objectDataString) {
Objects.requireNonNull(objectDataString, "objectDataString should not be null");
String[] customObjectComponents = objectDataString.split(":");
if (customObjectComponents.length != 2) {
throw new IllegalArgumentException("Malformed string: " + objectDataString);
}
EnumObjectType type = EnumObjectType.valueOf(customObjectComponents[0]);
try {
int value = Integer.parseInt(customObjectComponents[1]);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(customObjectComponents[1] + " is not an integer);
}
CustomObject singleObject = new CustomObject(type, value);
if (isValidCustomObject(singleObject)) {
return singleObject;
} else {
throw new IllegalArgumentException("Unknown custom object type/value: " + type + ":" + value);
}
}
And finally, it would probably make sense for the CustomObject's constructor to check whether its arguments are ok or not by itself, instead of having to call a separate isValid method. The last block would then simply be:
return new CustomObject(type, value);
which would throw an IllegalArgumentException from the constructor if required.
I have a program developed and it has a single entry point. A Try catch block is surrounding it.
try {
Runner runner = new Runner();
// Adhoc code
UIManager.setLookAndFeel(new NimbusLookAndFeel());
runner.setupVariables();
runner.setLookAndFeel();
runner.startSessionFactory();
runner.setupApplicationVariables();
runner.setupDirectories();
// This will be used to test out frames in development mode
if (Runner.isProduction == true) {
execute();
} else {
test();
}
} catch (Exception e) {
SwingHelper.showErrorMessageMainFrame(e.getMessage());
Logger.getRootLogger().error(e);
e.printStackTrace();
}
But suppose a null pointer exception is thrown, the message box is empty since the Exception doesn't contain a message. For this I added a logic-
if(e instanceof NullPointerException){
NullPointerException n =(NullPointerException) e;
SwingHelper.showErrorMessageMainFrame("Unexpected Exception due at ");
}else{
SwingHelper.showErrorMessageMainFrame(e.getMessage());
}
This works all fine but I also want the line number to be displayed. How can I get it done. How can I get the line number of the exception?
Among the answer to this question, you can use this snippet:
public static int getLineNumber() {
return Thread.currentThread().getStackTrace()[2].getLineNumber();
}
Althought is recommended to use a logging library such as log4j.
The metadata for the exception is stored in StackTraceElement class, which you can get from your exception by calling getStackTrace().
Example of using it is:
if (e instanceof NullPointerException) {
NullPointerException n = (NullPointerException) e;
StackTraceElement stackTrace = n.getStackTrace()[0];
SwingHelper.showErrorMessageMainFrame("Unexpected Exception due at " + stactTrace.getLineNumber());
}
if(e instanceof NullPointerException){
NullPointerException n =(NullPointerException) e;
SwingHelper.showErrorMessageMainFrame("Unexpected Exception due at line" + e.getStackTrace()[0].getLineNumber());
} else {
SwingHelper.showErrorMessageMainFrame(e.getMessage());
}
Wow I was ninja'd by those above...
EDIT: Forgot to indent
I am getting nullpointerexception, don't know what actually is causing it. I read from java docs that fileinputstream only throws securityexception so don't understand why this exception pops up.
here is my code snippet.
private Properties prop = new Properties();
private String settings_file_name = "settings.properties";
private String settings_dir = "\\.autograder\\";
public Properties get_settings() {
String path = this.get_settings_directory();
System.out.println(path + this.settings_dir + this.settings_file_name);
if (this.settings_exist(path)) {
try {
FileInputStream in = new FileInputStream(path + this.settings_dir + this.settings_file_name);
this.prop.load(in);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
} else {
this.create_settings_file(path);
try{
this.prop.load(new FileInputStream(path + this.settings_dir + this.settings_file_name));
}catch (IOException ex){
//ex.printStackTrace();
}
}
return this.prop;
}
private String get_settings_directory() {
String user_home = System.getProperty("user.home");
if (user_home == null) {
throw new IllegalStateException("user.home==null");
}
return user_home;
}
and here is my stacktrace:
C:\Users\mohamed\.autograder\settings.properties
Exception in thread "main" java.lang.NullPointerException
at autograder.Settings.get_settings(Settings.java:41)
at autograder.Application.start(Application.java:20)
at autograder.Main.main(Main.java:19)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)
Line 41 is: this.prop.load(in);
If line 41 is this.prop.load(in); then it seems as though this.prop == null
Add a breakpoint on the line to verify.
Attempting to call a method on a null instance results in a NullPointerException.
Is the variable prop null when it is executing on line 41? Try debugging your program to check this. e.g. add
if(prop == null)
System.out.println("prop is null");
Also, NullPointerException is an unchecked exception so isn't documented in Javadoc.
I think the other reviewers did a fair job in explaining your problem.
Couple of pointers:
I noticed that you are catching certain exceptions but not throwing them. If you do not throw the exception then there is no point in catching them.
Secondly, to avoid NPEs you should always check if any of your object is null before executing anything on the object.