ANN Switch Expressions in IntelliJ 2019.1 EAP

Brian Goetz brian.goetz at oracle.com
Wed Feb 27 22:52:37 UTC 2019


I got around to trying this out on the JDK.

Here's an example of where it correctly refactors:


if (caltype !=null) {
     switch (caltype) {
     case "buddhist":
     cal =new BuddhistCalendar(zone, aLocale);
         break;
     case "japanese":
         cal =new JapaneseImperialCalendar(zone, aLocale);
         break;
     case "gregory":
         cal =new GregorianCalendar(zone, aLocale);
         break;
     }

to

switch (caltype) {
     case "buddhist" -> cal =new BuddhistCalendar(zone, aLocale);
     case "japanese" -> cal =new JapaneseImperialCalendar(zone, aLocale);
     case "gregory" -> cal =new GregorianCalendar(zone, aLocale);
}

But, I would have expected it to do this instead:

cal =switch (caltype) {
     case "buddhist" ->new BuddhistCalendar(zone, aLocale);
     case "japanese" ->new JapaneseImperialCalendar(zone, aLocale);
     case "gregory" ->new GregorianCalendar(zone, aLocale);
}

The latter is much better style (expressions all the way down, less repetition, less error-prone).

Similarly, if each RHS is a cast to the same target, you may want to factor the cast out as well.

But, it gets it right when transforming something like:

private static CharPredicate getPosixPredicate(String name) {
     switch (name) {
         case "ALPHA":return ALPHABETIC();
         case "LOWER":return LOWERCASE();
         case "UPPER":return UPPERCASE();
         case "SPACE":return WHITE_SPACE();
         case "PUNCT":return PUNCTUATION();
         case "XDIGIT":return HEX_DIGIT();
         case "ALNUM":return ALNUM();
         case "CNTRL":return CONTROL();
         case "DIGIT":return DIGIT();
         case "BLANK":return BLANK();
         case "GRAPH":return GRAPH();
         case "PRINT":return PRINT();
         default:return null;
     }
}

the return is pulled out.

When transforming

switch (name) {
     case "ALPHABETIC":return ALPHABETIC();
     case "ASSIGNED":return ASSIGNED();
     case "CONTROL":return CONTROL();
     case "HEXDIGIT":return HEX_DIGIT();
     case "IDEOGRAPHIC":return IDEOGRAPHIC();
     case "JOINCONTROL":return JOIN_CONTROL();
     case "LETTER":return LETTER();
     case "LOWERCASE":return LOWERCASE();
     case "NONCHARACTERCODEPOINT":return NONCHARACTER_CODE_POINT();
     case "TITLECASE":return TITLECASE();
     case "PUNCTUATION":return PUNCTUATION();
     case "UPPERCASE":return UPPERCASE();
     case "WHITESPACE":return WHITE_SPACE();
     case "WORD":return WORD();
     case "WHITE_SPACE":return WHITE_SPACE();
     case "HEX_DIGIT":return HEX_DIGIT();
     case "NONCHARACTER_CODE_POINT":return NONCHARACTER_CODE_POINT();
     case "JOIN_CONTROL":return JOIN_CONTROL();
     default:return null;
}

I noticed it didn't merge, say, WHITESPACE and WHITE_SPACE with commas; it did offer to do that as a follow-on refactor.

Here's one it didn't try to transform at all, even though all paths are basically "status = ..; break":

switch (state) {
case NORMAL:
     status ="[Completed normally]";
     break;
case EXCEPTIONAL:
     status ="[Completed exceptionally: " +outcome +"]";
     break;
case CANCELLED:
case INTERRUPTING:
case INTERRUPTED:
     status ="[Cancelled]";
     break;
default:
     final Callable<?> callable =this.callable;
     status = (callable ==null)
         ?"[Not completed]" :"[Not completed, task = " + callable +"]";
}


I might factor the switch refactor into two; one for expressions and one for statements.  While the -> form is sometimes useful for statements, refactoring often doesn't gain nearly as much as for expressions.  Separating them allows people to set them at different levels of severity.



On 1/29/2019 12:49 PM, Anna Kozlova wrote:
> Hi all,
>
> we have initially supported switch expressions, please give it a try.
>
> The download link: https://www.jetbrains.com/idea/nextversion/
>
> Your feedback is very welcome.
> Thanks,
> Anna



More information about the amber-dev mailing list