-
Notifications
You must be signed in to change notification settings - Fork 0
/
chapter-14.txt
2873 lines (1766 loc) · 144 KB
/
chapter-14.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Chapter 14. Blocks, Statements, and Patterns
Table of Contents
14.1. Normal and Abrupt Completion of Statements
14.2. Blocks
14.3. Local Class and Interface Declarations
14.4. Local Variable Declarations
14.4.1. Local Variable Declarators and Types
14.4.2. Local Variable Declaration Statements
14.5. Statements
14.6. The Empty Statement
14.7. Labeled Statements
14.8. Expression Statements
14.9. The if Statement
14.9.1. The if-then Statement
14.9.2. The if-then-else Statement
14.10. The assert Statement
14.11. The switch Statement
14.11.1. Switch Blocks
14.11.1.1. Exhaustive Switch Blocks
14.11.1.2. Determining which Switch Label Applies at Run Time
14.11.2. The Switch Block of a switch Statement
14.11.3. Execution of a switch Statement
14.12. The while Statement
14.12.1. Abrupt Completion of while Statement
14.13. The do Statement
14.13.1. Abrupt Completion of do Statement
14.14. The for Statement
14.14.1. The basic for Statement
14.14.1.1. Initialization of for Statement
14.14.1.2. Iteration of for Statement
14.14.1.3. Abrupt Completion of for Statement
14.14.2. The enhanced for statement
14.15. The break Statement
14.16. The continue Statement
14.17. The return Statement
14.18. The throw Statement
14.19. The synchronized Statement
14.20. The try statement
14.20.1. Execution of try-catch
14.20.2. Execution of try-finally and try-catch-finally
14.20.3. try-with-resources
14.20.3.1. Basic try-with-resources
14.20.3.2. Extended try-with-resources
14.21. The yield Statement
14.22. Unreachable Statements
14.30. Patterns
14.30.1. Kinds of Patterns
14.30.2. Pattern Matching
14.30.3. Properties of Patterns
The sequence of execution of a program is controlled by statements, which are executed for their effect and do not have values.
Some statements contain other statements as part of their structure; such other statements are substatements of the statement. We say that statement S immediately contains statement U if there is no statement T different from S and U such that S contains T and T contains U. In the same manner, some statements contain expressions (§15 (Expressions)) as part of their structure.
The first section of this chapter discusses the distinction between normal and abrupt completion of statements (§14.1). Most of the remaining sections explain the various kinds of statements, describing in detail both their normal behavior and any special treatment of abrupt completion.
Blocks are explained first (§14.2), both because they can appear in certain places where statements are not allowed and because one kind of statement, a local variable declaration statement (§14.4.2), must be immediately contained by a block. Local class and interface declarations (§14.3) are not statements, but must also be immediately contained by a block.
Next, a grammatical maneuver that sidesteps the familiar "dangling else" problem (§14.5) is explained.
Every statement must be reachable in a certain technical sense (§14.22).
Sections 14.23-14.29 are unused to allow for the introduction of new kinds of statements in future.
The last section of this chapter (§14.30) describes patterns, which are used within statements and expressions to conditionally declare and initialize local variables. A pattern gives a concise description of how one value, such as an object, could be composed from one or more other values, denoted by variable declarations. Pattern matching attempts to extract one or more values from a given value, as if to decompose it, and uses the extracted values to initialize the variables declared by the pattern.
14.1. Normal and Abrupt Completion of Statements
Every statement has a normal mode of execution in which certain computational steps are carried out. The following sections describe the normal mode of execution for each kind of statement.
If all the steps are carried out as described, with no indication of abrupt completion, the statement is said to complete normally. However, certain events may prevent a statement from completing normally:
The break, yield, continue, and return statements (§14.15, §14.21, §14.16, §14.17) cause a transfer of control that may prevent normal completion of expressions, statements, and blocks that contain them.
Evaluation of certain expressions may throw exceptions from the Java Virtual Machine (§15.6). An explicit throw (§14.18) statement also results in an exception. An exception causes a transfer of control that may prevent normal completion of statements.
If such an event occurs, then execution of one or more statements may be terminated before all steps of their normal mode of execution have completed; such statements are said to complete abruptly.
An abrupt completion always has an associated reason, which is one of the following:
A break with no label
A break with a given label
A continue with no label
A continue with a given label
A return with no value
A return with a given value
A throw with a given value, including exceptions thrown by the Java Virtual Machine
A yield with a given value
The terms "complete normally" and "complete abruptly" also apply to the evaluation of expressions (§15.6). The only reason an expression can complete abruptly is that an exception is thrown, because of either a throw with a given value (§14.18) or a run-time exception or error (§11 (Exceptions), §15.6).
If a statement evaluates an expression, abrupt completion of the expression always causes the immediate abrupt completion of the statement, with the same reason. All succeeding steps in the normal mode of execution are not performed.
Unless otherwise specified in this chapter, abrupt completion of a substatement causes the immediate abrupt completion of the statement itself, with the same reason, and all succeeding steps in the normal mode of execution of the statement are not performed.
Unless otherwise specified, a statement completes normally if all expressions it evaluates and all substatements it executes complete normally.
14.2. Blocks
A block is a sequence of statements, local variable declaration statements, and local class and interface declarations within braces.
Block:
{ [BlockStatements] }
BlockStatements:
BlockStatement {BlockStatement}
BlockStatement:
LocalClassOrInterfaceDeclaration
LocalVariableDeclarationStatement
Statement
A block is executed by executing each of the local variable declaration statements and other statements in order from first to last (left to right). If all of these block statements complete normally, then the block completes normally. If any of these block statements complete abruptly for any reason, then the block completes abruptly for the same reason.
14.3. Local Class and Interface Declarations
A local class is a nested class (§8 (Classes)) whose declaration is immediately contained by a block (§14.2).
A local interface is a nested interface (§9 (Interfaces)) whose declaration is immediately contained by a block.
LocalClassOrInterfaceDeclaration:
ClassDeclaration
NormalInterfaceDeclaration
The following productions are shown here for convenience:
ClassDeclaration:
NormalClassDeclaration
EnumDeclaration
RecordDeclaration
NormalClassDeclaration:
{ClassModifier} class TypeIdentifier [TypeParameters] [ClassExtends] [ClassImplements] [ClassPermits] ClassBody
EnumDeclaration:
{ClassModifier} enum TypeIdentifier [ClassImplements] EnumBody
NormalInterfaceDeclaration:
{InterfaceModifier} interface TypeIdentifier [TypeParameters] [InterfaceExtends] [InterfacePermits] InterfaceBody
Local class and interface declarations may be intermixed freely with statements (including local variable declaration statements) in the containing block.
It is a compile-time error if a local class or interface declaration has any of the access modifiers public, protected, or private (§6.6).
It is a compile-time error if a local class or interface declaration has the modifier static (§8.1.1.4), sealed, or non-sealed (§8.1.1.2, §9.1.1.4).
It is a compile-time error if the direct superclass or a direct superinterface of a local class is sealed.
It is a compile-time error if a direct superinterface of a local interface is sealed.
A local class may be a normal class (§8.1), an enum class (§8.9), or a record class (§8.10). Every local normal class is an inner class (§8.1.3). Every local enum class and local record class is implicitly static (§8.1.1.4), and therefore not an inner class.
A local interface may be a normal interface (§9.1), but not an annotation interface (§9.6). Every local interface is implicitly static (§9.1.1.3).
Like an anonymous class (§15.9.5), a local class or interface is not a member of any package, class, or interface (§7.1, §8.5). Unlike an anonymous class, a local class or interface has a simple name (§6.2, §6.7).
The scope and shadowing of a local class or interface declaration is specified in §6.3 and §6.4.
Example 14.3-1. Local Class Declarations
Here is an example that illustrates several aspects of the rules given above:
class Global {
class Cyclic {}
void foo() {
new Cyclic(); // create a Global.Cyclic
class Cyclic extends Cyclic {} // circular definition
{
class Local {}
{
class Local {} // compile-time error
}
class Local {} // compile-time error
class AnotherLocal {
void bar() {
class Local {} // ok
}
}
}
class Local {} // ok, not in scope of prior Local
}
}
The first statement of method foo creates an instance of the member class Global.Cyclic rather than an instance of the local class Cyclic, because the statement appears prior to the scope of the local class declaration.
The fact that the scope of a local class declaration encompasses its whole declaration (not only its body) means that the definition of the local class Cyclic is indeed cyclic because it extends itself rather than Global.Cyclic. Consequently, the declaration of the local class Cyclic is rejected at compile time.
Since local class names cannot be redeclared within the same method (or constructor or initializer, as the case may be), the second and third declarations of Local result in compile-time errors. However, Local can be redeclared in the context of another, more deeply nested, class such as AnotherLocal.
The final declaration of Local is legal, since it occurs outside the scope of any prior declaration of Local.
14.4. Local Variable Declarations
A local variable declaration declares and optionally initializes one or more local variables (§4.12.3).
LocalVariableDeclaration:
{VariableModifier} LocalVariableType VariableDeclaratorList
LocalVariableType:
UnannType
var
See §8.3 for UnannType. The following productions from §4.3, §8.3, and §8.4.1 are shown here for convenience:
VariableModifier:
Annotation
final
VariableDeclaratorList:
VariableDeclarator {, VariableDeclarator}
VariableDeclarator:
VariableDeclaratorId [= VariableInitializer]
VariableDeclaratorId:
Identifier [Dims]
_
Dims:
{Annotation} [ ] {{Annotation} [ ]}
VariableInitializer:
Expression
ArrayInitializer
A local variable declaration can appear in the following locations:
a local variable declaration statement in a block (§14.4.2)
the header of a basic for statement (§14.14.1)
the header of an enhanced for statement (§14.14.2)
the resource specification of a try-with-resources statement (§14.20.3)
a pattern (§14.30.1)
The rules concerning annotation modifiers for a local variable declaration are specified in §9.7.4 and §9.7.5.
If the keyword final appears as a modifier for a local variable declaration, then the local variable is a final variable (§4.12.4).
It is a compile-time error if final appears more than once as a modifier for a local variable declaration.
It is a compile-time error if a local variable declaration that (i) does not include an Identifier and (ii) does not have an initializer, appears in any of the following locations:
a local variable declaration statement in a block (§14.4.2)
the header of a basic for statement (§14.14.1)
It is a compile-time error if the LocalVariableType is var and any of the following are true:
More than one VariableDeclarator is listed.
The VariableDeclaratorId has one or more bracket pairs.
The VariableDeclarator lacks an initializer.
The initializer of the VariableDeclarator is an ArrayInitializer.
The initializer of the VariableDeclarator contains a reference to the variable.
Example 14.4-1. Local Variables Declared With var
The following code illustrates these rules restricting the use of var:
var a = 1; // Legal
var b = 2, c = 3.0; // Illegal: multiple declarators
var d[] = new int[4]; // Illegal: extra bracket pairs
var e; // Illegal: no initializer
var f = { 6 }; // Illegal: array initializer
var g = (g = 7); // Illegal: self reference in initializer
These restrictions help to avoid confusion about the type being represented by var.
14.4.1. Local Variable Declarators and Types
Each declarator in a local variable declaration declares one local variable. If the declarator includes an Identifier then this is the name of the local variable, otherwise the local variable is unnamed (§6.1).
If the optional keyword final appears at the start of the declaration, the variable being declared is a final variable (§4.12.4).
The declared type of a local variable is determined as follows:
If the LocalVariableType is UnannType, and no bracket pairs appear in UnannType or VariableDeclaratorId, then the type of the local variable is denoted by UnannType.
If the LocalVariableType is UnannType, and bracket pairs appear in UnannType or VariableDeclaratorId, then the type of the local variable is specified by §10.2.
If the LocalVariableType is var, then let T be the type of the initializer expression when treated as if it did not appear in an assignment context, and were thus a standalone expression (§15.2). The type of the local variable is the upward projection of T with respect to all synthetic type variables mentioned by T (§4.10.5).
It is a compile-time error if T is the null type.
Because the initializer is treated as if it did not appear in an assignment context, an error occurs if it is a lambda expression (§15.27) or a method reference expression (§15.13).
The scope and shadowing of a local variable declaration is specified in §6.3 and §6.4.
References to a local variable from a nested class or interface, or a lambda expression, are restricted, as specified in §6.5.6.1.
Example 14.4.1-1. Type of Local Variables Declared With var
The following code illustrates the typing of variables declared with var:
var a = 1; // a has type 'int'
var b = java.util.List.of(1, 2); // b has type 'List<Integer>'
var c = "x".getClass(); // c has type 'Class<? extends String>'
// (see JLS 15.12.2.6)
var d = new Object() {}; // d has the type of the anonymous class
var e = (CharSequence & Comparable<String>) "x";
// e has type CharSequence & Comparable<String>
var f = () -> "hello"; // Illegal: lambda not in an assignment context
var g = null; // Illegal: null type
Note that some variables declared with var cannot be declared with an explicit type, because the type of the variable is not denotable.
Upward projection is applied to the type of the initializer when determining the type of the variable. If the type of the initializer contains capture variables, this projection maps the type of the initializer to a supertype that does not contain capture variables.
While it would be possible to allow the type of the variable to mention capture variables, by projecting them away we enforce an attractive invariant that the scope of a capture variable is never larger than the statement containing the expression whose type is captured. Informally, capture variables cannot "leak" into subsequent statements.
14.4.2. Local Variable Declaration Statements
A local variable declaration statement consists of a local variable declaration.
LocalVariableDeclarationStatement:
LocalVariableDeclaration ;
Every local variable declaration statement is immediately contained by a block, whereas other kinds of statement (§14.5) may be immediately contained by either a block or another statement.
In the containing block, local variable declaration statements may be intermixed freely with other kinds of statements and with local class and interface declarations.
A local variable declaration statement is an executable statement. Every time it is executed, the declarators are processed in order from left to right. If a declarator has an initializer, the initializer is evaluated and its value is assigned to the variable.
If a declarator does not have an initializer, then every reference to the variable must be preceded by execution of an assignment to the variable, or a compile-time error occurs by the rules of §16 (Definite Assignment).
Each initializer (except the first) is evaluated only if evaluation of the preceding initializer completes normally.
Execution of the local variable declaration statement completes normally only if evaluation of the last initializer completes normally.
If none of the declarators in a local variable declaration statement have an initializer, then executing the statement always completes normally.
14.5. Statements
There are many kinds of statements in the Java programming language. Most correspond to statements in the C and C++ languages, but some are unique.
As in C and C++, the if statement of the Java programming language suffers from the so-called "dangling else problem," illustrated by this misleadingly formatted example:
if (door.isOpen())
if (resident.isVisible())
resident.greet("Hello!");
else door.bell.ring(); // A "dangling else"
The problem is that both the outer if statement and the inner if statement might conceivably own the else clause. In this example, one might surmise that the programmer intended the else clause to belong to the outer if statement.
The Java programming language, like C and C++ and many programming languages before them, arbitrarily decrees that an else clause belongs to the innermost if to which it might possibly belong. This rule is captured by the following grammar:
Statement:
StatementWithoutTrailingSubstatement
LabeledStatement
IfThenStatement
IfThenElseStatement
WhileStatement
ForStatement
StatementNoShortIf:
StatementWithoutTrailingSubstatement
LabeledStatementNoShortIf
IfThenElseStatementNoShortIf
WhileStatementNoShortIf
ForStatementNoShortIf
StatementWithoutTrailingSubstatement:
Block
EmptyStatement
ExpressionStatement
AssertStatement
SwitchStatement
DoStatement
BreakStatement
ContinueStatement
ReturnStatement
SynchronizedStatement
ThrowStatement
TryStatement
YieldStatement
The following productions from §14.9 are shown here for convenience:
IfThenStatement:
if ( Expression ) Statement
IfThenElseStatement:
if ( Expression ) StatementNoShortIf else Statement
IfThenElseStatementNoShortIf:
if ( Expression ) StatementNoShortIf else StatementNoShortIf
Statements are thus grammatically divided into two categories: those that might end in an if statement that has no else clause (a "short if statement") and those that definitely do not.
Only statements that definitely do not end in a short if statement may appear as an immediate substatement before the keyword else in an if statement that does have an else clause.
This simple rule prevents the "dangling else" problem. The execution behavior of a statement with the "no short if" restriction is identical to the execution behavior of the same kind of statement without the "no short if" restriction; the distinction is drawn purely to resolve the syntactic difficulty.
14.6. The Empty Statement
An empty statement does nothing.
EmptyStatement:
;
Execution of an empty statement always completes normally.
14.7. Labeled Statements
Statements may have label prefixes.
LabeledStatement:
Identifier : Statement
LabeledStatementNoShortIf:
Identifier : StatementNoShortIf
The Identifier is declared to be the label of the immediately contained Statement.
Unlike C and C++, the Java programming language has no goto statement; identifier statement labels are used with break or continue statements (§14.15, §14.16) appearing anywhere within the labeled statement.
The scope of a label of a labeled statement is the immediately contained Statement.
It is a compile-time error if the name of a label of a labeled statement is used within the scope of the label as a label of another labeled statement.
There is no restriction against using the same identifier as a label and as the name of a package, class, interface, method, field, parameter, or local variable. Use of an identifier to label a statement does not obscure (§6.4.2) a package, class, interface, method, field, parameter, or local variable with the same name. Use of an identifier as a class, interface, method, field, local variable or as the parameter of an exception handler (§14.20) does not obscure a statement label with the same name.
A labeled statement is executed by executing the immediately contained Statement.
If the statement is labeled by an Identifier and the contained Statement completes abruptly because of a break with the same Identifier, then the labeled statement completes normally. In all other cases of abrupt completion of the Statement, the labeled statement completes abruptly for the same reason.
Example 14.7-1. Labels and Identifiers
The following code was taken from a version of the class String and its method indexOf, where the label was originally called test. Changing the label to have the same name as the local variable i does not obscure the label in the scope of the declaration of i. Thus, the code is valid.
class Test {
char[] value;
int offset, count;
int indexOf(TestString str, int fromIndex) {
char[] v1 = value, v2 = str.value;
int max = offset + (count - str.count);
int start = offset + ((fromIndex < 0) ? 0 : fromIndex);
i:
for (int i = start; i <= max; i++) {
int n = str.count, j = i, k = str.offset;
while (n-- != 0) {
if (v1[j++] != v2[k++])
continue i;
}
return i - offset;
}
return -1;
}
}
The identifier max could also have been used as the statement label; the label would not obscure the local variable max within the labeled statement.
14.8. Expression Statements
Certain kinds of expressions may be used as statements by following them with semicolons.
ExpressionStatement:
StatementExpression ;
StatementExpression:
Assignment
PreIncrementExpression
PreDecrementExpression
PostIncrementExpression
PostDecrementExpression
MethodInvocation
ClassInstanceCreationExpression
An expression statement is executed by evaluating the expression; if the expression has a value, the value is discarded.
Execution of the expression statement completes normally if and only if evaluation of the expression completes normally.
Unlike C and C++, the Java programming language allows only certain forms of expressions to be used as expression statements. For example, it is legal to use a method invocation expression (§15.12):
System.out.println("Hello world"); // OK
but it is not legal to use a parenthesized expression (§15.8.5):
(System.out.println("Hello world")); // illegal
Note that the Java programming language does not allow a "cast to void" - void is not a type - so the traditional C trick of writing an expression statement such as:
(void)... ; // incorrect!
does not work. On the other hand, the Java programming language allows all the most useful kinds of expressions in expression statements, and it does not require a method invocation used as an expression statement to invoke a void method, so such a trick is almost never needed. If a trick is needed, either an assignment statement (§15.26) or a local variable declaration statement (§14.4) can be used instead.
14.9. The if Statement
The if statement allows conditional execution of a statement or a conditional choice of two statements, executing one or the other but not both.
IfThenStatement:
if ( Expression ) Statement
IfThenElseStatement:
if ( Expression ) StatementNoShortIf else Statement
IfThenElseStatementNoShortIf:
if ( Expression ) StatementNoShortIf else StatementNoShortIf
The Expression must have type boolean or Boolean, or a compile-time error occurs.
14.9.1. The if-then Statement
An if-then statement is executed by first evaluating the Expression. If the result is of type Boolean, it is subjected to unboxing conversion (§5.1.8).
If evaluation of the Expression or the subsequent unboxing conversion (if any) completes abruptly for some reason, the if-then statement completes abruptly for the same reason.
Otherwise, execution continues by making a choice based on the resulting value:
If the value is true, then the contained Statement is executed; the if-then statement completes normally if and only if execution of the Statement completes normally.
If the value is false, no further action is taken and the if-then statement completes normally.
14.9.2. The if-then-else Statement
An if-then-else statement is executed by first evaluating the Expression. If the result is of type Boolean, it is subjected to unboxing conversion (§5.1.8).
If evaluation of the Expression or the subsequent unboxing conversion (if any) completes abruptly for some reason, then the if-then-else statement completes abruptly for the same reason.
Otherwise, execution continues by making a choice based on the resulting value:
If the value is true, then the first contained Statement (the one before the else keyword) is executed; the if-then-else statement completes normally if and only if execution of that statement completes normally.
If the value is false, then the second contained Statement (the one after the else keyword) is executed; the if-then-else statement completes normally if and only if execution of that statement completes normally.
14.10. The assert Statement
An assertion is an assert statement containing a boolean expression. An assertion is either enabled or disabled. If an assertion is enabled, execution of the assertion causes evaluation of the boolean expression and an error is reported if the expression evaluates to false. If the assertion is disabled, execution of the assertion has no effect whatsoever.
AssertStatement:
assert Expression ;
assert Expression : Expression ;
To ease the presentation, the first Expression in both forms of the assert statement is referred to as Expression1. In the second form of the assert statement, the second Expression is referred to as Expression2.
It is a compile-time error if Expression1 does not have type boolean or Boolean.
It is a compile-time error if, in the second form of the assert statement, Expression2 is void (§15.1).
An assert statement that is executed after its class or interface has completed initialization is enabled if and only if the host system has determined that the top level class or interface that lexically contains the assert statement enables assertions.
Whether a top level class or interface enables assertions is determined no later than the earliest of (i) the initialization of the top level class or interface, and (ii) the initialization of any class or interface nested in the top level class or interface. Whether a top level class or interface enables assertions cannot be changed after it has been determined.
An assert statement that is executed before its class or interface has completed initialization is enabled.
This rule is motivated by a case that demands special treatment. Recall that the assertion status of a class is set no later than the time it is initialized. It is possible, though generally not desirable, to execute methods or constructors prior to initialization. This can happen when a class hierarchy contains a circularity in its static initialization, as in the following example:
public class Foo {
public static void main(String[] args) {
Baz.testAsserts();
// Will execute after Baz is initialized.
}
}
class Bar {
static {
Baz.testAsserts();
// Will execute before Baz is initialized!
}
}
class Baz extends Bar {
static void testAsserts() {
boolean enabled = false;
assert enabled = true;
System.out.println("Asserts " +
(enabled ? "enabled" : "disabled"));
}
}
Invoking Baz.testAsserts() causes Baz to be initialized. Before this can happen, Bar must be initialized. Bar's static initializer again invokes Baz.testAsserts(). Because initialization of Baz is already in progress by the current thread, the second invocation executes immediately, though Baz is not initialized (§12.4.2).
Because of the rule above, if the program above is executed without enabling assertions, it must print:
Asserts enabled
Asserts disabled
A disabled assert statement does nothing. In particular, neither Expression1 nor Expression2 (if it is present) are evaluated. Execution of a disabled assert statement always completes normally.
An enabled assert statement is executed by first evaluating Expression1. If the result is of type Boolean, it is subjected to unboxing conversion (§5.1.8).
If evaluation of Expression1 or the subsequent unboxing conversion (if any) completes abruptly for some reason, the assert statement completes abruptly for the same reason.
Otherwise, execution continues by making a choice based on the value of Expression1:
If the value is true, no further action is taken and the assert statement completes normally.
If the value is false, the execution behavior depends on whether Expression2 is present:
If Expression2 is present, it is evaluated. Then:
If the evaluation completes abruptly for some reason, the assert statement completes abruptly for the same reason.
If the evaluation completes normally, an AssertionError instance whose "detail message" is the resulting value of Expression2 is created. Then:
If the instance creation completes abruptly for some reason, the assert statement completes abruptly for the same reason.
If the instance creation completes normally, the assert statement completes abruptly by throwing the newly created AssertionError object.
If Expression2 is not present, an AssertionError instance with no "detail message" is created. Then:
If the instance creation completes abruptly for some reason, the assert statement completes abruptly for the same reason.
If the instance creation completes normally, the assert statement completes abruptly by throwing the newly created AssertionError object.
Typically, assertion checking is enabled during program development and testing, and disabled for deployment, to improve performance.
Because assertions may be disabled, programs must not assume that the expressions contained in assertions will be evaluated. Thus, these boolean expressions should generally be free of side effects. Evaluating such a boolean expression should not affect any state that is visible after the evaluation is complete. It is not illegal for a boolean expression contained in an assertion to have a side effect, but it is generally inappropriate, as it could cause program behavior to vary depending on whether assertions were enabled or disabled.
In light of this, assertions should not be used for argument checking in public methods. Argument checking is typically part of the contract of a method, and this contract must be upheld whether assertions are enabled or disabled.
A secondary problem with using assertions for argument checking is that erroneous arguments should result in an appropriate run-time exception (such as IllegalArgumentException, ArrayIndexOutOfBoundsException, or NullPointerException). An assertion failure will not throw an appropriate exception. Again, it is not illegal to use assertions for argument checking on public methods, but it is generally inappropriate. It is intended that AssertionError never be caught, but it is possible to do so, thus the rules for try statements should treat assertions appearing in a try block similarly to the current treatment of throw statements.
14.11. The switch Statement
The switch statement transfers control to one of several statements or expressions, depending on the value of an expression.
SwitchStatement:
switch ( Expression ) SwitchBlock
The Expression is called the selector expression. The type of the selector expression must be char, byte, short, int, or a reference type, or a compile-time error occurs.
14.11.1. Switch Blocks
The body of both a switch statement and a switch expression (§15.28) is called a switch block. This subsection presents general rules which apply to all switch blocks, whether they appear in switch statements or switch expressions. Other subsections present additional rules which apply either to switch blocks in switch statements (§14.11.2) or to switch blocks in switch expressions (§15.28.1).
SwitchBlock:
{ SwitchRule {SwitchRule} }
{ {SwitchBlockStatementGroup} {SwitchLabel :} }
SwitchRule:
SwitchLabel -> Expression ;
SwitchLabel -> Block
SwitchLabel -> ThrowStatement
SwitchBlockStatementGroup:
SwitchLabel : {SwitchLabel :} BlockStatements
SwitchLabel:
case CaseConstant {, CaseConstant}
case null [, default]
case CasePattern {, CasePattern} [Guard]
default
CaseConstant:
ConditionalExpression
CasePattern:
Pattern
Guard:
when Expression
A switch block can consist of either:
Switch rules, which use -> to introduce either a switch rule expression, a switch rule block, or a switch rule throw statement; or
Switch labeled statement groups, which use : to introduce switch labeled block statements.
Every switch rule and switch labeled statement group starts with a switch label, which is either a case label or a default label. Multiple switch labels are permitted for a switch labeled statement group.
A case label has either a (non-empty) list of case constants, a null literal, or a (non-empty) list of case patterns.
Every case constant must be either a constant expression (§15.29), or the name of an enum constant (§8.9.1), otherwise a compile-time error occurs.
A case label with a null literal may have an optional default.
A case label with case patterns may have an optional when expression, known as a guard, which represents a further test on values that match the patterns. A case label is said to be unguarded if either (i) it has no guard, or (ii) it has a guard that is a constant expression (§15.29) with value true; and guarded otherwise.
It is a compile-time error for a case label to have more than one case pattern and declare any pattern variables (other than those declared by a guard associated with the case label).
If a case label with more than one case pattern could declare pattern variables, then it would not be clear which variables would be initialized if the case label were to apply. For example:
Object obj = ...;
switch (obj) {
case Integer i, Boolean b -> {
... // Error! Is i or b initialized?
}
...
}
Even if only one of the case patterns declares a pattern variable, it would still not be clear whether the variable was initialized or not; for example:
Object obj = ...;
switch (obj) {
case Integer i, Boolean _ -> {
... // Error! Is i initialized?
}
...
}
The following does not result in a compile-time error:
Object obj = ...;
switch (obj) {
case Integer _, Boolean _ -> {
... // Matches both an Integer and a Boolean
}
...
}
Switch labels and their case constants, null literals, and case patterns are said to be associated with the switch block.
For a given switch block both of the following must be true, otherwise a compile-time error occurs:
No two of the case constants associated with a switch block may have the same value.
No more than one null literal may be associated with a switch block.
No more than one default label may be associated with a switch block.
A guard associated with a case label must satisfy all of the following conditions, otherwise a compile-time error occurs:
A guard must have type boolean or Boolean.
Any local variable, formal parameter, or exception parameter used but not declared in a guard must either be final or effectively final (§4.12.4).
Any blank final variable used but not declared in a guard must be definitely assigned (§16 (Definite Assignment)) before the guard.
A guard cannot be a constant expression (§15.29) with the value false.
The switch block of a switch statement or a switch expression is switch compatible with the type of the selector expression, T, if all of the following are true:
If a null literal is associated with the switch block, then T is a reference type.
For every case constant associated with the switch block that names an enum constant, the type of the case constant is assignment compatible with T (§5.2).
For each case constant associated with the switch block that is a constant expression, the constant is assignment compatible with T, and T is one of char, byte, short, int, Character, Byte, Short, Integer, or String.
Every pattern p associated with the switch block is applicable at type T (§14.30.3).
Switch blocks are not designed to work with the types boolean, long, float, and double. The selector expression of a switch statement or switch expression can not have one of these types.
The switch block of a switch statement or a switch expression must be switch compatible with the type of the selector expression, or a compile-time error occurs.
A switch label in a switch block is said to be dominated if for every value that it applies to, it can be determined that one of the preceding switch labels would also apply. It is a compile-time error if any switch label in a switch block is dominated. The rules for determining whether a switch label is dominated are as follows:
A case label with a case pattern q is dominated if there is a preceding unguarded case label in the switch block with a case pattern p, and p dominates q (§14.30.3).
The definition of one pattern dominating another pattern is based on types. For example, the type pattern Object o dominates the type pattern String s, and so the following results in a compile-time error:
Object obj = ...
switch (obj) {
case Object o ->
System.out.println("An object");
case String s -> // Error!
System.out.println("A string");
}
A guarded case label with a case pattern is dominated by a case label with the same pattern but without the guard. For example, the following results in a compile-time error:
String str = ...;
switch (str) {
case String s ->
System.out.println("A string");
case String s when s.length() == 2 -> // Error!
System.out.println("Two character string");
...
}
On the other hand, a guarded case label with a case pattern is not considered to dominate an unguarded case label with the same case pattern. This allows the following common pattern programming style:
Integer j = ...;
switch (j) {
case Integer i when i <= 0 ->
System.out.println("Less than or equal to zero");
case Integer i ->
System.out.println("An integer");
}
The only exception is where the guard is a constant expression that has the value true, for example:
Integer j = ...;
switch (j) {
case Integer i when true -> // Ok
System.out.println("An integer");
case Integer i -> // Error!
System.out.println("An integer");
}
A case label with more than one case pattern is dominated if any one of these patterns is dominated by a pattern that appears as a case pattern in a preceding unguarded case label, and so the following results in a compile-time error (as the type pattern Integer _ is dominated by the type pattern Number _):
Object obj = ...
switch (obj) {
case Number _ ->
System.out.println("A Number");
case Integer _, String _ -> // Error - dominated!
System.out.println("An Integer or a String");
...
}
A case label with a case constant c is dominated if one of the following holds:
c is a constant expression of a primitive type S, and there is a preceding case label in the switch block with an unguarded case pattern p, where p is unconditional for the wrapper class of S.
c is a constant expression of a reference type T, and there is a preceding case label in the switch block with an unguarded case pattern p, where p is unconditional for the type T.
c names an enum constant of enum class E, and there is a preceding case label in the switch block with an unguarded case pattern p, where p is unconditional for the type E.
For example, a case label with an Integer type pattern dominates a case label with an integer literal:
Integer j = ...;
switch (j) {
case Integer i ->
System.out.println("An integer");
case 42 -> // Error - dominated!
System.out.println("42!");
}
A default label or a case null, default label is dominated if there is a preceding unguarded case label in the switch block with a case pattern p where p is unconditional for the type of the selector expression (§14.30.3).
A case label with a case pattern that is unconditional for the type of the selector expression will, as the name suggests, match every value and so behave like a default label. A switch block can not have more than one switch label that acts like a default.
It is a compile-time error if there is a case label with n (n>1) case patterns p1, ..., pn in a switch block where one of the patterns pi (1≤i<n) dominates another of the patterns pj (i<j≤n).
It is a compile-time error if any of the following holds:
There is a default label in the switch block that precedes a case label with case patterns.
There is a default label in the switch block that precedes a case label with a null literal.
There is a case null, default label in the switch block followed by any other switch label.
If used, a default label should come last in a switch block.
For compatibility reasons, a default label may appear before case labels that do not have a null literal or case patterns.
int i = ...;
switch(i) {
default ->
System.out.println("Some other integer");
case 42 -> // allowed
System.out.println("42");
}
If used, a case null, default label should come last in a switch block.
It is a compile-time error if, in a switch block that consists of switch labeled statement groups, a statement is labeled with a case label that declares one or more pattern variables (§6.3.3), and either:
An immediately preceding statement in the switch block can complete normally (§14.22), or
The statement is labeled with more than one switch label.
The first condition prevents a statement group from "falling through" to another statement group without initializing pattern variables. For example, were the statement labeled by case Integer i reachable from the preceding statement group, the pattern variable i would not have been initialized:
Object o = "Hello";
switch (o) {
case String s:
System.out.println("String: " + s ); // No break!
case Integer i:
System.out.println(i + 1); // Error! Can be reached
// without matching the
// pattern `Integer i`
default:
}
Switch blocks consisting of switch label statement groups allow multiple labels to apply to a statement group. The second condition prevents a statement group from being executed based on one label without initializing the pattern variables of another label. For example:
Object o = "Hello World";
switch (o) {
case String s:
case Integer i:
System.out.println(i + 1); // Error! Can be reached
// without matching the
// pattern `Integer i`
default:
}
Object obj = null;
switch (obj) {
case null:
case String s:
System.out.println(s); // Error! Can be reached
// without matching the
// pattern `String s`
default:
}
Both of these conditions apply only when the case pattern declares pattern variables. The following examples, in contrast, are unproblematic:
record R() {}
record S() {}
Object o = "Hello World";
switch (o) {
case String s:
System.out.println(s); // No break
case R(): // No pattern variables declared
System.out.println("It's either an R or a string");
break;
default:
}
Object ob = new R();
switch (ob) {
case R():
case S(): // Multiple case labels
System.out.println("Either R or an S");
break;
default:
}
Object obj = null;
switch (obj) {
case null:
case R(): // Multiple case labels
System.out.println("Either null or an R");
break;
default:
}
14.11.1.1. Exhaustive Switch Blocks
The switch block of a switch expression or switch statement is exhaustive for a selector expression e if one of the following cases applies:
There is a default label associated with the switch block.
There is a case null, default label associated with the switch block.
The set containing all the case constants and case patterns appearing in an unguarded case label (collectively known as case elements) associated with the switch block is non-empty and covers the type of the selector expression e.
A set of case elements, P, covers a type T if one of the following cases applies:
P covers a type U where T and U have the same erasure.
P contains a pattern that is unconditional for T.
T is a type variable with upper bound B and P covers B.
T is an intersection type T1& ... &Tn and P covers Ti, for one of the types Ti (1≤ i ≤ n).
The type T is an enum class type E and P contains all of the names of the enum constants of E.
A default label is permitted, but not required, in the case where the names of all the enum constants appear as case constants. For example:
enum E { F, G, H }
static int testEnumExhaustive(E e) {
return switch(e) {
case F -> 0;
case G -> 1;
case H -> 2; // No default required!
};
}
The type T names an abstract sealed class or sealed interface C and for every permitted direct subclass or subinterface D of C, one of the following two conditions holds:
There is no type that both names D and is a subtype of T, or
There is a type U that both names D and is a subtype of T, and P covers U.
A default label is permitted, but not required, in the case where the switch block exhausts all the permitted direct subclasses and subinterfaces of an abstract sealed class or sealed interface. For example:
sealed interface I permits A, B, C {}
final class A implements I {}
final class B implements I {}
record C(int j) implements I {} // Implicitly final
static int testExhaustive1(I i) {
return switch(i) {
case A a -> 0;
case B b -> 1;