如何在不使用try-catch的情况下使用Java时忽略可能的ClassNotFoundException
我有一个类,其方法仅在该类存在时才返回该类,如果未加载类路径,调用该方法将生成由ClassNotFoundException引起的如何在不使用try-catch的情况下使用Java时忽略可能的ClassNotFoundException,java,reflection,classnotfoundexception,Java,Reflection,Classnotfoundexception,我有一个类,其方法仅在该类存在时才返回该类,如果未加载类路径,调用该方法将生成由ClassNotFoundException引起的NoClassDefFoundError异常(这是正确的,因为它不是强制性的) 当某些方法(或字段)可能未加载到类路径中时,如何从类#getMethods()获取方法?在检索方法/字段时是否可以忽略它们 请注意,使用try-catch将完全阻止整个过程工作,因此这不是解决方案 下面是我加载类的方式: try { String name = StringUtil
NoClassDefFoundError
异常(这是正确的,因为它不是强制性的)
当某些方法(或字段)可能未加载到类路径中时,如何从类#getMethods()获取方法?在检索方法/字段时是否可以忽略它们
请注意,使用try-catch将完全阻止整个过程工作,因此这不是解决方案强>
下面是我加载类的方式:
try {
String name = StringUtil.format("Nifty{0}", (isBungee ? "Bungee" : "Bukkit"));
Reflection main = new Reflection(name, StringUtil.format("net.netcoding.{0}", name.toLowerCase())); // net.netcoding.niftybukkit.NiftyBukkit
Object mainObj = main.invokeMethod("getPlugin", null); // See below
logger = (Logger)main.invokeMethod("getLogger", mainObj);
} catch (Exception ex) { }
以下是尝试在反射中定位方法的两个位:
public class Reflection {
private static final transient ConcurrentHashMap<Class<?>, Class<?>> CORRESPONDING_TYPES = new ConcurrentHashMap<>();
private final String className;
private final String subPackage;
private final String packagePath;
static {
CORRESPONDING_TYPES.put(Byte.class, byte.class);
CORRESPONDING_TYPES.put(Short.class, short.class);
CORRESPONDING_TYPES.put(Integer.class, int.class);
CORRESPONDING_TYPES.put(Long.class, long.class);
CORRESPONDING_TYPES.put(Character.class, char.class);
CORRESPONDING_TYPES.put(Float.class, float.class);
CORRESPONDING_TYPES.put(Double.class, double.class);
CORRESPONDING_TYPES.put(Boolean.class, boolean.class);
}
public Reflection(String className, String packagePath) {
this(className, "", packagePath);
}
public Reflection(String className, String subPackage, String packagePath) {
this.className = className;
this.subPackage = StringUtil.stripNull(subPackage).replaceAll("\\.$", "").replaceAll("^\\.", "");
this.packagePath = packagePath;
}
public String getClassName() {
return this.className;
}
public String getClassPath() {
return this.getPackagePath() + (StringUtil.notEmpty(this.subPackage) ? "." + this.subPackage : "") + "." + this.getClassName();
}
public Class<?> getClazz() throws Exception {
return Class.forName(this.getClassPath());
}
public Object invokeMethod(String name, Object obj, Object... args) throws Exception {
return this.getMethod(name, toPrimitiveTypeArray(args)).invoke(obj, args);
}
private static Class<?> getPrimitiveType(Class<?> clazz) {
return clazz != null ? CORRESPONDING_TYPES.containsKey(clazz) ? CORRESPONDING_TYPES.get(clazz) : clazz : null;
}
public Method getMethod(String name, Class<?>... paramTypes) throws Exception {
Class<?>[] types = toPrimitiveTypeArray(paramTypes);
// In this example, this.getClazz() simply returns
// a Class of net.netcoding.niftybukkit.NiftyBukkit
// this.getClazz().getMethods() throws the ClassNotFOundException
// I want to still access the methods, even if one of them is not available
for (Method method : this.getClazz().getMethods()) {
Class<?>[] methodTypes = toPrimitiveTypeArray(method.getParameterTypes());
if (method.getName().equals(name) && isEqualsTypeArray(methodTypes, types)) {
method.setAccessible(true);
return method;
}
}
System.out.println(StringUtil.format("The method {0} was not found with parameters {1}!", name, Arrays.asList(types)));
return null;
}
公共类反射{
私有静态最终瞬态ConcurrentHashMap>对应的_类型=新ConcurrentHashMap();
私有最终字符串类名;
私有最终字符串子包;
私有最终字符串包路径;
静止的{
对应的_类型put(Byte.class,Byte.class);
对应的_类型put(Short.class,Short.class);
对应的_类型put(Integer.class,int.class);
对应的_类型put(Long.class,Long.class);
对应的_类型.put(Character.class,char.class);
对应的_类型put(Float.class,Float.class);
对应的_类型put(Double.class,Double.class);
对应的_类型.put(Boolean.class,Boolean.class);
}
公共反射(字符串类名称、字符串包路径){
这(类名称,“,packagePath);
}
公共反射(字符串类名称、字符串子包、字符串包路径){
this.className=className;
this.subPackage=StringUtil.stripNull(subPackage).replaceAll(“\\\.$”,“”)。replaceAll(“^\.”,“”);
this.packagePath=packagePath;
}
公共字符串getClassName(){
返回this.className;
}
公共字符串getClassPath(){
返回this.getPackagePath()+(StringUtil.notEmpty(this.subPackage)?“+this.subPackage:”)+“+this.getClassName();
}
公共类getClazz()引发异常{
返回Class.forName(this.getClassPath());
}
公共对象invokeMethod(字符串名称、对象obj、对象…args)引发异常{
返回此.getMethod(名称,toPrimitiveTypeArray(args)).invoke(obj,args);
}
私有静态类getPrimitiveType(类clazz){
return clazz!=null?对应的_类型。containsKey(clazz)?对应的_类型。get(clazz):clazz:null;
}
公共方法getMethod(字符串名称、类…paramTypes)引发异常{
类[]类型=TopPrimitiveTypeArray(paramTypes);
//在本例中,this.getClazz()只返回
//一类net.netcoding.niftybukkit.niftybukkit
//这个.getClazz().getMethods()抛出ClassNotFOundException
//我仍然希望访问这些方法,即使其中一个不可用
对于(方法:this.getClazz().getMethods()){
类[]methodTypes=toPrimitiveTypeArray(method.getParameterTypes());
if(method.getName().equals(name)和&isequalTypeArray(methodTypes,types)){
方法setAccessible(true);
返回法;
}
}
System.out.println(StringUtil.format(“找不到参数为{1}!、名称、数组、asList(类型))的方法{0}”);
返回null;
}
关于:
public Class<?> getClazz() {
try {
return Class.forName(this.getClassPath());
} catch (ClassNotFoundException e) {
// ignore or better log
}
return null;
}
public类getClazz(){
试一试{
返回Class.forName(this.getClassPath());
}catch(classnotfounde异常){
//忽略或更好地记录
}
返回null;
}
随后:
Class<?> clazz = this.getClazz();
if (clazz != null) {
for (Method method : clazz.getMethods()) {
// ....
}
}
Class clazz=this.getClazz();
if(clazz!=null){
for(方法:clazz.getMethods()){
// ....
}
}
如果保留您的设计,您将创建依赖于非保证行为的不可移植代码
如果一个方法的返回类型引用了一个不可用的类,那么如果该方法的代码试图处理该类的缺失(returnnull
或其他什么),或者该方法没有被调用,那么它就没有帮助
不仅是类.getMethods
可能失败,还可能导致整个类不可用。问题是,如果无法解析直接引用的类,JVM可以自由决定何时抛出错误。一个有效点是类加载时间,因此,对于不同的JVM,可以实现这样的解析策略y、 您甚至无法调用Class.getMethods()
让有效代码处理可选类的唯一方法是将直接引用的类与可选类解耦,例如
public static BaseType getOptionalFeature() {
try {
return (BaseType)Class.forName("OptionalType").newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
return null;
}
}
假设OptionalType
扩展或实现了BaseType
,那么重要的一点是BaseType
是一个始终可用的类型,所有非可选代码总是通过BaseType
引用可选功能。您可能会有更多的代码直接访问OptionalType
,这是您认为的如果OptionalType
不可用,则不调用e,但也必须使用动态类加载将其与非可选代码分离
否则,您在急切地解析JVM时会面临完全失败的风险,而在懒洋洋地解析像Oracle这样的JVM时会面临虚假失败的风险。如果您不调用有问题的方法,它不会立即失败这一事实并不能保证您的行为——这只是一种优化。要么加载一个类,要么定义所有方法ods是可用的,或者它没有加载,然后你就什么都没有了。你说有些方法(或字段)可能没有加载到类路径中是什么意思?我提供了一个帮助器方法来检索注册的服务,但是如果插件不在那里,它就不会被使用;但是