首页 > 代码库 > 连抛2个异常,第一个是第二个的Cause

连抛2个异常,第一个是第二个的Cause

异常只能抛一个,捕捉到再抛一个,也只是一个异常

看下面的代码,如果你认为执行不到(如果 if 条件满足)执行不到第2个 throwException 就错了 (Jeallybean code)

libcore/luni/src/main/native/libcore_io_Posix.cpp#throwException

    146 static void throwGaiException(JNIEnv* env, const char* functionName, int error) {
    147     if (errno != 0) {
    148         // EAI_SYSTEM should mean "look at errno instead", but both glibc and bionic seem to
    149         // mess this up. In particular, if you don't have INTERNET permission, errno will be EACCES
    150         // but you'll get EAI_NONAME or EAI_NODATA. So we want our GaiException to have a
    151         // potentially-relevant ErrnoException as its cause even if error != EAI_SYSTEM.
    152         // http://code.google.com/p/android/issues/detail?id=15722
    153         throwErrnoException(env, functionName);
    154         // Deliberately fall through to throw another exception...
    155     }
    156     static jmethodID ctor3 = env->GetMethodID(JniConstants::gaiExceptionClass,
    157             "<init>", "(Ljava/lang/String;ILjava/lang/Throwable;)V");
    158     static jmethodID ctor2 = env->GetMethodID(JniConstants::gaiExceptionClass,
    159             "<init>", "(Ljava/lang/String;I)V");
    160     throwException(env, JniConstants::gaiExceptionClass, ctor3, ctor2, functionName, error);
    161 }

因为这不是  native C++ 自己的exception,而是 native 送给 java 层的 exception

再看下面的函数,如果在有 Pending Exception 的情况下(env->ExceptionOccurred), Pending Exception 将成为当前Exception 的 cause

    113 static void throwException(JNIEnv* env, jclass exceptionClass, jmethodID ctor3, jmethodID ctor2,
    114         const char* functionName, int error) {
    115     jthrowable cause = NULL;
    116     if (env->ExceptionCheck()) {
    117         cause = env->ExceptionOccurred();
    118         env->ExceptionClear();
    119     }
    120 
    121     ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
    122     if (detailMessage.get() == NULL) {
    123         // Not really much we can do here. We're probably dead in the water,
    124         // but let's try to stumble on...
    125         env->ExceptionClear();
    126     }
    127 
    128     jobject exception;
    129     if (cause != NULL) {
    130         exception = env->NewObject(exceptionClass, ctor3, detailMessage.get(), error, cause);
    131     } else {
    132         exception = env->NewObject(exceptionClass, ctor2, detailMessage.get(), error);
    133     }
    134     env->Throw(reinterpret_cast<jthrowable>(exception));
    135 }

再看下面

libcore/luni/src/main/java/java/net/InetAddress.java#getAllByNameImpl

    417         } catch (GaiException gaiException) {
    418             // If the failure appears to have been a lack of INTERNET permission, throw a clear
    419             // SecurityException to aid in debugging this common mistake.
    420             // http://code.google.com/p/android/issues/detail?id=15722
    421             if (gaiException.getCause() instanceof ErrnoException) {
    422                 if (((ErrnoException) gaiException.getCause()).errno == EACCES) {
    423                     throw new SecurityException("Permission denied (missing INTERNET permission?)", gaiException);
    424                 }
    425             }
    426             // Otherwise, throw an UnknownHostException.
    427             String detailMessage = "Unable to resolve host \"" + host + "\": " + Libcore.os.gai_strerror(gaiException.error);
    428             addressCache.putUnknownHost(host, detailMessage);
    429             throw gaiException.rethrowAsUnknownHostException(detailMessage);
    430         }

检测到GaiException的时候,正好检查 Cause 是否是 ErrnoException



连抛2个异常,第一个是第二个的Cause