Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-7190387

multi-catch incorrectly exemplified as sequence of uni-catch

    XMLWordPrintable

Details

    • 7
    • x86
    • linux_ubuntu
    • Verified

    Description

      FULL PRODUCT VERSION :
      $ java -version
      java version "1.7.0_05"
      Java(TM) SE Runtime Environment (build 1.7.0_05-b05)
      Java HotSpot(TM) 64-Bit Server VM (build 23.1-b03, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      $ uname -a
      Linux d-ubuntu12x64-02 3.2.0-23-generic #36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux


      A DESCRIPTION OF THE PROBLEM :
      Section 14.20, "The try statement" of JLS-7 (JSR-000901) erroneously describes multi-catch clauses as semantically equivalent to a sequence of uni-catch clauses on page 403 (of the PDF form available at http://docs.oracle.com/javase/specs). The erroneous text is:

      <begin quote>
      A multi-catch clause can be thought of as a sequence of uni-catch clauses. That is, a catchclause whose exception parameter type is denoted as a union D1|D2|...|Dn is equivalent to a sequence of n catch clauses whose exception parameters have class types D1, D2, ..., Dn, respectively. For example, the following code:

      try {
          ... throws ReflectiveOperationException ...
      }
      catch (ClassNotFoundException | IllegalAccessException ex) {
          ... body ...
      }

      is semantically equivalent to the following code:

      try {
          ... throws ReflectiveOperationException ...
      } catch (final ClassNotFoundException ex1) {
          ... body ...
      } catch (final IllegalAccessException ex2) {
          ... body ...
      }

      whereby the multi-catch clause with two alternatives has been translated into two separate catch clauses, one for each alternative. A Java compiler is neither required nor recommended to compile a multi-catch clause by duplicating code in this manner, since it is possible to represent the multi-catchclause in a classfile without duplication.
      <end quote>

      As written, each body in the uni-catch code variant would be evaluated using the final class type as specified in each catch clause. This contrasts with the multi-catch code variant in which the body of the multi-catch clause would be evaluated using the least upper bound super type of the multi-catch clause parameter. This difference affects method overload resolution as can be seen in the sample code included with this bug report.

      The text can be corrected by replacing the uni-catch clause code variant as follows and noting that ReflectiveOperationException is the least upper bound super type of ClassNotFoundException and IllegalAccessException.

      try {
          ... throws ReflectiveOperationException ...
      } catch (final ClassNotFoundException ex1) {
          final ReflectiveOperationException ex = ex1;
          ... body ...
      } catch (final IllegalAccessException ex2) {
          final ReflectiveOperationException ex = ex2;
          ... body ...
      }

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      The source code included with this bug report demonstrates that a naive translation of a multi-catch clause into a sequence of uni-catch clauses is not necessarily semantically equivalent. The test case contains two try statements. The first uses a multi-catch clause and the second uses only uni-catch clauses expanded as described in the JLS 7 text. Running the program illustrates that different results are produced.


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      public class t {
          public static void main(String[] args) {
              try {
                  if (args.length == 0 || args[0].equals("1")) {
                      throw new ExceptionType1();
                  } else {
                      throw new ExceptionType2();
                  }
              } catch(ExceptionType1 | ExceptionType2 ex) {
                  DoSomething(ex);
              }

              try {
                  if (args.length == 0 || args[0].equals("1")) {
                      throw new ExceptionType1();
                  } else {
                      throw new ExceptionType2();
                  }
              } catch(final ExceptionType1 ex) {
                  DoSomething(ex);
              } catch(final ExceptionType2 ex) {
                  DoSomething(ex);
              }
          }

          static class ExceptionTypeBase extends Exception { }
          static class ExceptionType1 extends ExceptionTypeBase { }
          static class ExceptionType2 extends ExceptionTypeBase { }

          static void DoSomething(ExceptionTypeBase ex) {
              System.out.println("DoSomething(ExceptionTypeBase)");
          }

          static void DoSomething(ExceptionType1 ex) {
              System.out.println("DoSomething(ExceptionType1)");
          }

          static void DoSomething(ExceptionType2 ex) {
              System.out.println("DoSomething(ExceptionType2)");
          }
      }

      ---------- END SOURCE ----------

      Attachments

        Issue Links

          Activity

            People

              abuckley Alex Buckley
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: