Check if a class exists without throwing a ClassNotFoundException

To schedule a job, I get the class name as a string input.
This class can be in one of two packages, but I do not know which one I need to check.

I currently have two try-catch blocks

Class<Job> clazz; String className; //the above mentioned string, will be initialized try { clazz = (Class<Job>) Class.forName("package.one." + className); } catch (ClassNotFoundException ex) { try { clazz = (Class<Job>) Class.forName("package.two." + className); } catch (ClassNotFoundException ex1) { //some error handling code here, as the class is //in neither of the two packages } } 

For more packages, this will become uglier and more unreadable. Moreover, this is - for me - against the concept of exceptions, since exceptions should not be expected / used to control the flow!
Is there a way to rewrite this without using a ClassNotFoundException ?

+6
source share
4 answers

I would stick with the Class.forName method for this.

You can store class and package names in Collection or Set and scroll through these elements. When you get a ClassNotFoundException , you just continue the search. If you don't get the exception, you exit the loop with break , since you found the class you were looking for.

The reason for Class.forName is that it loads the class for you if it has not already been loaded by the virtual machine. This is a pretty powerful side effect.

This basically eliminates the need to dig up all CLASSPATH and look for class files to load into the virtual machine and solve problems such as the class is already loaded or not using the virtual machine.

EDIT:

Jacob Jenkov has written some really great Java articles / tutorials. I found them extremely useful when working with reflection, class loaders, and concurrency (some of the β€œmost complex” aspects of Java).

Here's a good article on the Java class loader if you still decide not to use Class.forName .

+5
source
 public Class<Job> getClass(String className) { String packages[] = { "package.one.", "package.two." }; for (int j = 0; j < packages.length; j++) { try { return (Class<Job>) Class.forName(packages[j] + className); } catch (ClassNotFoundException ex) { System.out.println("Package "+packages[j]+" is not worked"); } } return null; } 
+4
source

You can use the Guava Reflection utilities to get the ClassInfo of each class loaded in the classpath.

 ClassLoader classLoader = ClassLoader.getSystemClassLoader(); ClassPath classPath = ClassPath.from(classLoader); ImmutableSet<ClassInfo> set = classPath.getTopLevelClasses(); for (ClassInfo ci : set) { System.out.println(ci.getName()); } 

In a loop, you can implement your own logic for loading a class using the className that you provide.

+3
source

In this case, I would not worry about using a ClassNotFoundException . Although you can generally make sure that you do not use exceptions to control the flow, here it is hardly considered to be such.

I would probably wrap it in a function like

 public static String getPackageForClass(String className, String... packageNames) { for (String packageName : packageNames) { try { Class.forName(packageName + className); return packageName; } catch (ClassNotFoundException ignored) { } } return ""; } 

or return the class directly if you wish

 public static Class getPackageForClass(String className, String... packageNames) { for (String packageName : packageNames) { try { return Class.forName(packageName + className); } catch (ClassNotFoundException ignored) { } } return null; } 
+1
source

Source: https://habr.com/ru/post/957489/


All Articles