I have a method which looks for animals species in a file and I'd like it to throw an error when a specie don't exist in my database
public void printAnimalFromNames(String... s){
try (Stream<String> stream = Arrays.stream(s)) {
stream.forEach(x -> printAnimalPage(AnimalInfo.get(findSpecie(x))));
} catch (Exception e){
System.out.println("this spiece don't seem to exist");
}
}
in my catch part I'd like to put the x variable that throw the exeption in my error explanation like
[...]
catch (Exception e){
System.out.println("this spiece "+x+" don't seem to exist");
}
how can I do ?
You'll have to move the try-catch inside the body of the lambda, as that's where the lambda parameter, x, is in scope:
public void printAnimalFromNames(String... s) {
try (Stream<String> stream = Arrays.stream(s)) {
stream.forEach(x -> {
try {
printAnimalPage(AnimalInfo.get(findSpecie(x)));
} catch (Exception e) {
System.out.println("this specie " + x + " don't seem to exist");
}
});
}
}
Related
I’m using Javassist (3.25.0-GA) and Java 8 with a custom Agent to transform bytecode and add print statements to existing catch{} clauses. This works for simple cases, but has a problem with the compiled bytecode of the try-with-resources syntax.
Here is a basic example of what I'm trying to do and the results when it works correctly on standard try/catch blocks:
// before byte code manipulation
public void methodWithCatchClause() {
try {
throwsAnException();
} catch (Exception ex) {
handleException(ex);
}
}
// after byte code manipulation
public void methodWithCatchClause() {
try {
throwsAnException();
} catch (Exception ex) {
System.out.println("CATCH CLAUSE!"); // added by Javassist
handleException(ex);
}
}
The logic I'm using to transform the bytecode is inspired by another SO post [0]:
// from https://stackoverflow.com/questions/51738034/javassist-insert-a-method-at-the-beginning-of-catch-block
ControlFlow cf = new ControlFlow(ctMethod); // ctMethod == methodWithCatchClause()
for (ControlFlow.Block block : cf.basicBlocks()) {
ControlFlow.Catcher catchers[] = block.catchers();
for (int i = 0; i < catchers.length; i++) {
ControlFlow.Catcher catcher = catchers[i];
ControlFlow.Block catcherBlock = catcher.block();
int position = catcherBlock.position();
int lineNumber = ctMethod.getMethodInfo().getLineNumber(position);
ctMethod.insertAt(lineNumber + 1, "System.out.println(\"CATCH CLAUSE!\");");
}
}
But this code breaks in conjunction with the try-with-resources syntax. As a concrete example this code:
public void tryWithResources() {
try (TestAutoClosable test = new TestAutoClosable()) {
test.doStuff();
} catch (Exception ex) {
handleException(ex);
}
}
Turns into this after code generation:
public void tryWithResources() {
try {
TestAutoClosable test = new TestAutoClosable();
Throwable var2 = null;
try {
System.out.println("CATCH CLAUSE!");
test.doStuff();
} catch (Throwable var12) {
var2 = var12;
throw var12;
} finally {
if (test != null) {
if (var2 != null) {
try {
test.close();
} catch (Throwable var11) {
var2.addSuppressed(var11);
}
} else {
test.close();
}
}
}
} catch (Exception var14) {
System.out.println("CATCH CLAUSE!");
System.out.println("CATCH CLAUSE!");
System.out.println("CATCH CLAUSE!");
// this goes on for 15 more entries...
this.handleException(var14);
}
}
This of course is causing "CATCH CLAUSE!" to be printed multiple times in odd places. It might be helpful to mention that empty catch clauses, regardless of try/catch syntax, break in a similar fashion (maybe the underlying cause is related?).
I would expect something closer to this as the end result:
public void tryWithResources() {
try {
TestAutoClosable test = new TestAutoClosable();
Throwable var2 = null;
try {
test.noop();
} catch (Throwable var12) {
System.out.println("CATCH CLAUSE!");
var2 = var12;
throw var12;
} finally {
if (test != null) {
if (var2 != null) {
try {
test.close();
} catch (Throwable var11) {
var2.addSuppressed(var11);
}
} else {
test.close();
}
}
}
} catch (Exception var14) {
this.handleException(var14);
}
}
I'm trying to figure out if I have a simple error in my code or if my approach is entirely wrong. I would appreciate any help with the matter. Thanks in advance.
[0] Javassist: insert a method at the beginning of catch block
Can somebody tell me what am I doing wrong in the below java code ? It doesn't compile and gives me compilation error.
import java.io.*;
public class ShowFile {
public static void main(String[] args) {
int i;
FileInputStream Fin;
try {
Fin = new FileInputStream("C:\\Users\\cbr\\Desktop\\test.txt");
} catch (FileNotFoundException exp) {
System.out.println("exception caught" + exp);
}
try {
do {
i = Fin.read();
System.out.print((char) i);
} while (i != -1);
} catch (IOException exp) {
System.out.println("Exception caught" + exp);
}
finally {
try {
Fin.close();
} catch (IOException exp) {
System.out.println("Exception caught" + exp);
}
}
}
}
while the below code compiles. You can see both initialization are within try block.
import java.io.*;
class ShowFile2 {
public static void main(String args[]) {
int i;
FileInputStream fin;
// First make sure that a file has been specified.
try {
fin = new FileInputStream("C:\\Users\\cbr\\Desktop\\test.txt");
} catch (FileNotFoundException exc) {
System.out.println("File Not Found");
return;
}
try {
// read bytes until EOF is encountered
do {
i = fin.read();
if (i != -1) {
System.out.print((char) i);
}
} while (i != -1);
} catch (IOException exc) {
System.out.println("Error reading file.");
}
try {
fin.close();
} catch (IOException exc) {
System.out.println("Error closing file.");
}
}
}
The problem is, that if new FileInputStream("C:\\Users\\cbr\\Desktop\\test.txt"); throws an exception, your variable will not be initialized in the second part of your method. This is not allowed. Object members will be initialized to null when the object is created, but this is not the case for local variables: they must be initialized explicitly.
A quick fix (but read on for a better fix) would be to initialize your variable (to null) when you are defining it:
FileInputStream fin = null;
This will solve your compilation error, however, you will get NullPointerExceptions when an exception is thrown in the first catch block.
A better solution is to put your error handling logic in the same place: if creating the FileInputStream fails, you don't want to read bytes from it anyway. So you can use a single try-catch block:
try {
fin = new FileInputStream("C:\\Users\\cbr\\Desktop\\test.txt");
// Read bytes from fin.
...
} catch (IOException e) {
// handle exception
...
}
Final advice: to make sure that your input stream is closed in all circumstances, you can use a try-with-resources block:
try (fin = new FileInputStream("C:\\Users\\cbr\\Desktop\\test.txt")) {
// Read bytes from fin.
...
} catch (IOException e) {
// handle exception
...
}
It does compile because the ShowFile2 class contains return in the catch block: this will ensure that the variable fin will be always initialized.
In the first class you caught the exception and you continue the execution of your program.
I am new to programming and have a noob question. I am trying to run a test like so...
#Test
public void rememberTest()
throws DuplicateException{
try{
personA.remember(sighting4);
}
catch (Exception e) {
fail("Failed" + e.getMessage());
}
try{
assertEquals(personA.remember(sighting3), "The list already contains this sighting");
}
catch (Exception e) {
fail("Failed" + e.getMessage());
}
}
the first try/catch compiles but the second one does not. It tells me "'void' type not allowed here.
" Why can't I use a void? If I can't use a void type, then how would I build my test so that the exception is thrown?
some background info: rememberTest is a test of the remember method that adds an item to an ArrayList.
the remember method, in Class Person, is as follows:
public void remember(final Sighting s)
throws DuplicateException
{
if(lifeList.contains(s)) {
throw new DuplicateException("The list already contains this sighting");
}
lifeList.remember(s);
}
If you need more info please request and I will post it as required.
since you method has already ensured that no duplicate value will be added then I suggest to remove the assertEquals from your code,
#Test
public void rememberTest()
throws DuplicateException{
try{
personA.remember(sighting4);
}
catch (Exception e) {
fail("Failed" + e.getMessage());
}
try{
personA.remember(sighting3), //this will throws Exception if sighting3 is already in.
}
catch (Exception e) {
fail("Failed" + e.getMessage());
}
}
to demonstrate edit your code to this:
#Test
public void rememberTest()
throws DuplicateException{
Sighting s1=//initialize s1
Sighting s2=s1;
try{
personA.remember(s1);
}
catch (Exception e) {
fail("Failed" + e.getMessage());
}
try{
personA.remember(s2), //This will throw an exception because s1 and s2 are pointed to the same object
}
catch (Exception e) {
fail("Failed" + e.getMessage());
}
}
I think instead of doing assert you should use the #Expected annotation which expects for the DuplicateException since its a test case
for the purpose of throwing the exception and catching it in the test Class, do some such thing as this:
try{
personA.remember(sightingSame);
}
catch (DuplicateException e) {
assertEquals("The list already contains this sighting", e.getMessage());
}
catch (Exception e) {
fail("Failed" + e.getMessage());
}
Is there a way to remove a previously added code block in Javassist?
I'm working on a project which modifies .class files via Javassist. Among other things it adds some code into constructors. I want this process to be runnable on the same .class file again and again without any side effects. However at the moment, after each run the same code is added to constructor one more time.
Is there a way to prevent this?
If you know the code to remove you can do it with Javassist easily:
In the next example this will remove all lines that contains the method "printStackTrace" of any "Exception" class, all the magic occurs with the instrument and replace methods
...
ClassPool cp = ClassPool.getDefault();
try{
CtClass ct = cp.getCtClass("com.cm.main.ConcretClass");
CtMethod m = ct.getDeclaredMethod("testException");
m.instrument(new ExprEditor() {
public void edit(MethodCall m) throws CannotCompileException {
String regexPattern = ".*Exception";
if (m.getClassName().matches(regexPattern) && m.getMethodName().matches("printStackTrace")) {
m.replace(";");
}
}
;
});
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (BadBytecode badBytecode) {
badBytecode.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
...
The ConcretClass:
public class ConcretClass{
public String getName() {
return this.name + "-Extra";
}
public void testException(){
try {
FileOutputStream file = new FileOutputStream("C:\\Temp\\downloads");
file.close();
} catch (FileNotFoundException e2) {
e2.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In the example below, you can see that the IOException (named FOURTH) exception cannot be caught using the outer catch clause. Why is that?
I know exceptions can be caught if its thrown in a nested try block, using outer catch.
If you change the b static variable value to false then you can see this.
But why cant we catch the exception thrown in a nested catch clause using an outer catch?
import java.io.*;
public class Exceptions {
static boolean b = true;
public static void main(String[] args){
try {
exceptions(b);
} catch (Exception e) {
System.out.println(e + " is handled by main().");
}
}
static void exceptions(boolean b) throws Exception{
try{
if(b) throw new FileNotFoundException("FIRST");
try{
throw new IOException("SECOND");
}
catch(FileNotFoundException e){
System.out.println("This will never been printed out.");
}
}
catch(FileNotFoundException e){
System.out.println(e + " is handled by exceptions().");
try{
throw new FileNotFoundException("THIRD");
}
catch(FileNotFoundException fe){
System.out.println(fe + " is handled by exceptions() - nested.");
}
try{
throw new IOException("FOURTH");
}
finally{}
}
catch(Exception e){
System.out.println(e + " is handled by exceptions().");
}
}
}
The output if b = true :
java.io.FileNotFoundException: FIRST is handled by exceptions(). java.io.FileNotFoundException: THIRD is handled by exceptions() - nested. java.io.IOException: FOURTH is handled by main().
The output if b = false:
java.io.IOException: SECOND is handled by exceptions().
But why cant we catch the exception thrown in a nested catch clause using an outer catch?
You can. The problem is that your last catch(Exception e) is at the same level of nesting which is why it doesn't catch an exception thrown in a previous catch block.
Try nesting your try/catch blocks like this
static void exceptions(boolean b) {
try {
try {
if (b) throw new FileNotFoundException("FIRST");
try {
throw new IOException("SECOND");
} catch (FileNotFoundException e) {
System.out.println("This will never been printed out.");
}
} catch (FileNotFoundException e) {
System.out.println(e + " is handled by exceptions().");
try {
throw new FileNotFoundException("THIRD");
} catch (FileNotFoundException fe) {
System.out.println(fe + " is handled by exceptions() - nested.");
}
// will be caught by the nested try/catch at the end.
throw new IOException("FOURTH");
}
} catch (Exception e) {
System.out.println(e + " is handled by exceptions().");
}
}
Your structure is some thing like this
try {
//operation
}
catch (Exce 1){ //catch 1
// throw IO
}
catch(Exce 2){ //catch 2
// print error
}
Here catch1 and catch2 are at same level, and the exception thrown from catch1 will not reach catch2.
Hence Your IOE will be thrown back to the caller . If you want to handle the exception with in the method, then follow some thing below
try{
try {
//operation
}
catch (Exce 1){ //catch 1
// throw IO
}
catch(Exce 2){ //catch 2
// print error
}
}
catch(Exce 3) {
// your IO will be caught here
}