Всем известно, что кидать исключения можно только, если объект наследуется от класса java.lang.Throwable. Для этого предназначена инструкция байткода ATHROW. Мне стало интересно, осуществляется ли проверка типа после компиляции.
Напишем небольшой метод, генерирующий нужный класс, с помощью библиотеки bcel.

Объявим класс ru.izebit.Test

String className = "ru.izebit.Test";
ClassGen classGenerator = new ClassGen(className, "java.lang.Object", "Test", Const.ACC_PUBLIC, new String[0]);
InstructionFactory instructionFactory = new InstructionFactory(classGenerator);

Содержащий метод public static void main(String[] args) в котором вызывается метод test() и следом идет инструкция выхода из метода.

InstructionList instructionListOfMainMethod = new InstructionList();
InstructionHandle invokeHandler = instructionListOfMainMethod.append(
instructionFactory.createInvoke(className, "test", Type.VOID, Type.NO_ARGS, Const.INVOKESTATIC));
instructionListOfMainMethod.append(InstructionFactory.createReturn(Type.VOID));

Добавим команды для вывода в консоль сообщения об исключении, которые будут выполняться, если оно возникнет:

InstructionHandle catchBlock = instructionListOfMainMethod.append(
                                               instructionFactory.createFieldAccess(
                                                                            "java.lang.System", 
                                                                            "out",
                                                                            new ObjectType("java.io.PrintStream"), 
                                                                            Const.GETSTATIC));
 instructionListOfMainMethod.append(InstructionConst.DUP);
 instructionListOfMainMethod.append(
                                              new PUSH(classGenerator.getConstantPool(), 
                                              "An exception has been caught"));
 instructionListOfMainMethod.append(
                                               instructionFactory.createInvoke(
                                                                            "java.io.PrintStream", 
                                                                            "println", 
                                                                            Type.VOID, 
                                                                            new Type[]{Type.STRING}, 
                                                                            Const.INVOKEVIRTUAL));
 instructionListOfMainMethod.append(InstructionFactory.createReturn(Type.VOID));

Определим сигнатуру метода:

MethodGen mainMethodGenerator = new MethodGen(
                                              Const.ACC_PUBLIC | Const.ACC_STATIC,
                                              Type.VOID, 
                                              new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"},
                                              "main", 
                                              className,
                                              instructionListOfMainMethod, 
                                              classGenerator.getConstantPool());

И объявим в методе try-catch блок отлавливающий исключения типа java.lang.Object

mainMethodGenerator.addExceptionHandler(
                                          invokeHandler,
                                          invokeHandler.getNext(), 
                                          catchBlock, 
                                          ObjectType.getInstance("java/lang/Object"));
classGenerator.addMethod(mainMethodGenerator.getMethod());

Теперь напишем реализацию для метода test(). Создадим объект класса java.lang.Object и вызовем для него конструктор, следом вызовем throw и пробросим этот объект:

InstructionList instructionListOfTestMethod = new InstructionList();
instructionListOfTestMethod.append(instructionFactory.createNew("java/lang/Object"));
instructionListOfTestMethod.append(InstructionConst.DUP);
instructionListOfTestMethod.append(
                instructionFactory.createInvoke(
                                       "java/lang/Object",
                                       "<init>",
                                       Type.VOID, 
                                       Type.NO_ARGS, 
                                       Const.INVOKESPECIAL));
instructionListOfTestMethod.append(InstructionConst.ATHROW);
 instructionListOfTestMethod.append(InstructionFactory.createReturn(Type.VOID));

Добавим сигнатуру для метода public static test() throw Object :

MethodGen testMethodGenerator = new MethodGen(
                                    Const.ACC_PUBLIC | Const.ACC_STATIC,
                                    Type.VOID, 
                                    Type.NO_ARGS, 
                                    new String[0],
                                    "test", 
                                    className,
                                    instructionListOfTestMethod, 
                                    classGenerator.getConstantPool());
 testMethodGenerator.addException("java/lang/Object");
 testMethodGenerator.stripAttributes(true);
 testMethodGenerator.setMaxStack();
 testMethodGenerator.setMaxLocals();
 classGenerator.addMethod(testMethodGenerator.getMethod());

После этого, сохраним полученный класс в файл:

String outputPath = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath() + "ru/izebit/Test.class";
try (FileOutputStream fos = new FileOutputStream(outputPath)) {
      classGenerator.getJavaClass().dump(fos);
}

Содержимое файла, если его декомпилировать будет следующее:

package ru.izebit;

public class Test {
    public static void main(String[] args) {
        try {
            test();
        } catch (Object var1) {
            System.out.println("An exception has been caught");
        }
    }

    public static void test() throws Object {
        throw new Object();
    }
}

Попробуем запустить:

java ru.izebit.Test

Error: Unable to initialize main class ru.izebit.Test
Caused by: java.lang.VerifyError: (class: ru/izebit/Test, method: test signature: ()V) Can only throw Throwable objects

Верификатор байткода не позволил выполнить код, но его всегда можно выключить добавив нужный флаг:

java -Xverify:none ru.izebit.Test

После этого программы запустилась и успешно выполнилась, результат работы:

An exception has been caught

код целиком по ссылке ниже