Java 13 introduced the yield keyword for switch expressions.
How can I use it and what's the difference to a default return or break value?
Q&A
How can I use it?
With arrow labels when a full block is needed:
int value = switch (greeting) {
case "hi" -> {
System.out.println("I am not just yielding!");
yield 1;
}
case "hello" -> {
System.out.println("Me too.");
yield 2;
}
default -> {
System.out.println("OK");
yield -1;
}
};
With traditional blocks:
int value = switch (greeting) {
case "hi":
System.out.println("I am not just yielding!");
yield 1;
case "hello":
System.out.println("Me too.");
yield 2;
default:
System.out.println("OK");
yield -1;
};
What's the difference to a default return?
A return statement returns control to the invoker of a method (§8.4, §15.12) or constructor (§8.8, §15.9) while a yield statement transfers control by causing an enclosing switch expression to produce a specified value.
What's the difference to a break value?
The break with value statement is dropped in favour of a yield statement.
Specification
There is Specification for JEP 354 attached to the JLS 13 which sums up everything we need to know about the new switch. Note that it wasn't merged into the language specification because it's still a preview feature and, thus, not yet a permanent part of the language.
A yield statement transfers control by causing an enclosing switch expression to produce a specified value.
YieldStatement:
yield Expression;
A yield statement attempts to transfer control to the innermost enclosing switch expression; this expression, which is called the yield target, then immediately completes normally and the value of the Expression becomes the value of the switch expression.
It is a compile-time error if a yield statement has no yield target.
It is a compile-time error if the yield target contains any method, constructor, initializer, or lambda expression that encloses the yield statement.
It is a compile-time error if the Expression of a yield statement is void (15.1).
Execution of a yield statement first evaluates the Expression. If the evaluation of the Expression completes abruptly for some reason, then the yield statement completes abruptly for that reason. If evaluation of the Expression completes normally, producing a value V, then the yield statement completes abruptly, the reason being a yield with value V.
As part of JEP 354 (Java 13), you can yield value in switch (optionally assign it to variable)
yield statement to yield a value, which becomes the value of the enclosing switch expression.
int j = switch (day) {
case MONDAY -> 0;
case TUESDAY -> 1;
default -> {
int k = day.toString().length();
int result = f(k);
yield result;
}
};
I think your confusion is with JEP 325 on Java 12 that use break to return value:
we have extended the break statement to take an argument, which becomes the value of the enclosing switch expression.
int j = switch (day) {
case MONDAY -> 0;
case TUESDAY -> 1;
default -> {
int k = day.toString().length();
int result = f(k);
break result;
In addition, you can even use lambda syntax
boolean result = switch (ternaryBool) {
case TRUE -> true;
case FALSE -> false;
case FILE_NOT_FOUND -> throw new UncheckedIOException(
"This is ridiculous!",
new FileNotFoundException());
// as we'll see in "Exhaustiveness", `default` is not necessary
default -> throw new IllegalArgumentException("Seriously?! 🤬");
};
With switch expressions, the entire switch block "gets a value" that can then be assigned; you can use a lambda-style syntax
While Java 12 introduces and 13 refines switch expressions, they do so as a preview language feature. That means (a) it can still change over the next few releases (as it did between 12 and 13) and (b) it needs to be unlocked, at compile time and run time, with the new command line option --enable-preview. Then keep in mind that this isn’t the endgame for switch – it’s just a step on the way to full pattern matching.
yield marks value to be returned from a switch branch. It terminates the switch expression, you don't need to have break after it.
From doc
The two statements, break (with or without a label) and yield,
facilitate easy disambiguation between switch statements and switch
expressions: a switch statement but not a switch expression can be the
target of a break statement; and a switch expression but not a switch
statement can be the target of a yield statement.
It also provides, NullPointerException Safety,
String message = switch (errorCode) {
case 404:
yield "Not found!";
case 500:
yield "Internal server error!";
// No default
};
This will result in,
the switch expression does not cover all possible input values
break replace with yield in java 13. This is one of the preview feature defined in java 13.in Java 12, we can use break to return a value from a switch. But in java 13 yield use for the return value from switch expression.
In Java 13 break replace by yield,
String number = switch (number) {
case 1:
yield "one";
case 2:
yield "two";
default:
yield "Zero";
}
Arrow syntax is still supported in Java 13.
String number = switch (number) {
case 1 -> "one";
case 2 -> "two";
default -> "Zero";
}
Related
I found one interesting way to use a switch statement in Java, and I can't catch all logic.
Can someone help to understand all details in depth?
Here is code:
private static int counter = 0;
public static Shape randomFactory() {
int xVal = rand.nextInt(100);
int yVal = rand.nextInt(100);
int dim = rand.nextInt(100);
switch (counter++ % 3) {
default:
case 0:
return new Circle(xVal, yVal, dim);
case 1:
return new Square(xVal, yVal, dim);
case 2:
return new Line(xVal, yVal, dim);
}
}
In general I understand this logic,
What exactly default mean here:
switch (counter++ % 3) {
default:
And how does switch (counter++ % 3) find equals case? And here isn't any brake presented.
Any suggestions?
default marks the block that would get executed if the switch expression does not match any case labels. In your example, default contains no break, so it would fall through and execute the same code as for case 0.
Note that, since you have a case label for every possible value of the switch expression, the default is effectively a no-op.
In your case you are using default block at the very beginning of case statement, which is a bit strange since default means that this part of code will execute if none of the case conditions have matched. You should also check about fall through. You avoided it with returns, but it is usually done with break.
switch (counter++ % 3) calculates first counter++ % 3 and then matches it with appropriate case.
The default clause is useless here: due to your %3 it should never happen.
Would you modify the %3 to %4 it would catch some data, but as there is neither a break nor a return statement it would execute just like case 0.
default:
It simply means of none of the conditions in switch statement are matched code corresponding to default will be executed.
default will execute when there is no matching in case.In this case default is useless since it will never execute. Consider the following case.
switch(input){
case 1:
// do something
break;
case 2:
// do something
break;
default:
// if input is not 1 or 2 this will execute.
break;
}
Default is one of the switch labels which contains statements to execute if none of the other labels match. From JLS §14.11:
At most one default label may be associated with the same switch statement.
If no case matches but there is a default label, then all statements after the matching default label in the switch block, if any, are executed in sequence. If all these statements complete normally, or if there are no statements after the default label, then the entire switch statement completes normally.
If no case matches and there is no default label, then no further action is taken and the switch statement completes normally.
So in this case default label will do nothing as there always will be a match.
There is no break inside default so it do nothing, it is just example of fallthrough.
Please read about switch statements from here -
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
default means if any case doesn't match with switch condition then default is called.
counter++ % 3 ..your counter was 0 so it will match with case 0.
What is the best way to check if variable is bigger than some number using switch statement? Or you reccomend to use if-else? I found such an example:
int i;
if(var1>var2) i = 1;
if(var1=var2 i = 0;
if(var1<var2) i = -1;
switch (i);
{
case -1:
do stuff;
break;
case 0:
do stuff;
break;
case 1:
do stuff;
break;
}
What can you tell a novice about using "greater than or equal" in switch statements?
Not sure if this is what you're asking, but you could do it this way:
int var1;
int var2;
int signum = Long.signum((long)var1 - var2);
switch(signum) {
case -1: break;
case 0: break;
case 1: break;
}
I would strongly recommend a if(var1>var2){}else if (var1==var2) {} else {} construct. Using a switch here will hide the intent. And what if a break is removed by error?
Switch is useful and clear for enumerated values, not for comparisons.
First a suggestion: switch as it states should only be used for switching and not for condition checking.
From JLS switch statements
SwitchStatement:
switch ( Expression ) SwitchBlock
Expressions convertible to int or Enum are supported in the expression.
These labels are said to be associated with the switch statement, as
are the values of the constant expressions (§15.28) or enum constants
(§8.9.1) in the case labels.
Only constant expressions and Enum constants are allowed in switch statements for 1.6 or lower with java 7 String values are also supported. No logical expressions are supported.
Alternatively you can do as given by #Stewart in his answer.
Java only supports direct values, not ranges in case statements, so if you must use a switch, mapping to options first, then switching on that, as in the example you provide is your only choice. However that is quite excessive - just use the if statements.
A switch statement is for running code when specific values are returned, the if then else allows you to select a range of values in one statement. I would recommend doing something like the following (though I personnally prefer the Integer.signum method) should you want to look at multiple ranges:
int i;
if (var1 > var2) {
i = 1;
}
else if (var1 == var2) {
i = 0;
}
else {
i = -1;
}
You're better off with the if statements; the switch approach is much less clear, and in this case, your switch approach is objectively wrong. The contract for Comparable#compareTo does not require returning -1 or 1, just that the value of the returned int be negative or positive. It's entirely legitimate for compareTo to return -42, and your switch statement would drop the result.
If one variable's value is used, use switch. If multiple variables are in play, use if. In your stated problem, it should be if.
Unfortunately you cannot do that in java. It's possible in CoffeeScript or other languages.
I would recommend to use an if-else-statement by moving your "do stuff" in extra methods. In that way you can keep your if-else in a clearly readable code.
So basically given the below code.
When action = 2; and mode = 1 Will i ever be set to 2?
I am working on a colleagues code, and it is written like this, but I thought that break would just skip the if and continue the rest of case 2. So basically the if statement is pointless.
switch(action){
case 1: i = 1; break;
case 2: if(mode == 1)
{
break;
}
i = 2;
break;
case 3: i = 3; break;
Ive rewritten this as:
case 2: if(mode != 1)
i = 2;
break;
But it is not the only place, and some more complex. If im going to refactor it I need some info that I am correct.
There's no such a thing as an "if loop." Break can never refer to an "if" statement.
See Wasserman's answer for a pointer to the language specification.
Also, assuming that 1 <= action <= 3, your code simplifies to:
if(! (action == 2 && mode == 1)) {
i = action;
}
JLS section 14.15:
A break statement transfers control out of an enclosing statement.
BreakStatement:
break Identifieropt ;
A break statement with no label attempts to transfer control to the innermost enclosing switch, while, do, or for statement (emphasis added) of the immediately enclosing method or initializer block; this statement, which is called the break target, then immediately completes normally.
your refactoring is correct if that's what you want to know.
If action == 2 and mode == 1, i = 2 will not be executed (why you don't test it? It would be faster than asking here).
But your improvement is anyways cleaner, I would use it.
Is breaking and continuing the only uses of labeled statements in Java?
When have you used Labeled Statements in your programs?
Sorry the code snippet has been deleted. I am splitting the question
JLS 14.7 Labeled statements
(edited for clarity)
Statements may have label prefixes (Identifier : Statement). 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 (§14.15) or continue (§14.16) statements appearing anywhere within the labeled statement.
So the JLS is clear that labels are used with break or continue, and no other grammatical element of the Java programming language uses it.
Strictly speaking, break and continue, labeled or not, are NEVER necessary. They can always be written out of the code. Used idiomatically, however, they can lead to more readable code.
Here's an illustrative example: given an int[], we want to :
print "One (1)" on 1
print "Two (2)" on 2
print "Zero " on 0
immediately stop processing on any other number
int[] arr = { 1, 2, 0, 1, -1, 0, 2 };
loop:
for (int num : arr) {
switch (num) {
case 1:
System.out.print("One ");
break;
case 2:
System.out.print("Two ");
break;
case 0:
System.out.print("Zero ");
continue loop;
default:
break loop;
}
System.out.print("(" + num + ") ");
}
// prints "One (1) Two (2) Zero One (1) "
Here we see that:
The different numbers are processed in a switch
Unlabeled break in the switch is used to avoid "fall-through" between cases
Labeled continue loop; is used to skip post-processing on case 0: (the label is not necessary here)
Labeled break loop; is used to terminate the loop on default: (the label is necessary here; otherwise it's a switch break)
So labeled break/continue can also be used outside of nested loops; it can be used when a switch is nested inside a loop. More generally, it's used when there are potentially multiple break/continue target, and you want to choose one that is not immediately enclosing the break/continue statement.
Here's another example:
morningRoutine: {
phase1: eatBreakfast();
if (grumpy) break morningRoutine;
phase2: kissWife();
phase3: hugChildren();
}
http://stackoverflow.com is the best website ever!
Here's another case of a labeled break being used not within an iterative statement, but rather within a simple block statement. One may argue that the labels lead to better readability; this point is subjective.
And no, the last line DOES NOT give compile time error. It's actually inspired by Java Puzzlers Puzzle 22: Dupe of URL. Unfortunately, the puzzle does not go into "proper" use of labeled statements in more depth.
Yes, break and continue are the only two uses for labeled statements in Java. (Java has no goto statement.)
You can use a label to break out of nested loops.
outer:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
System.out.println("Hello");
continue outer;
} // end of inner loop
System.out.println("outer"); // Never prints
}
System.out.println("Good-Bye");
When you continue back to the outer label, you're skipping the remainder of both the inner and the outer loop, including the print statement.
search:
for (i = 0; i < arrayOfInts.length; i++) {
for (j = 0; j < arrayOfInts[i].length; j++) {
if (arrayOfInts[i][j] == searchfor) {
foundIt = true;
break search;
}
}
}
I have a yes or no question & answer. I would like to ask another yes or no question if yes was the answer. My instructor wants us to use charAt(0) as input for the answer.
Is it possible to have a switch statement within another one (like a nested if statement)?
EDIT: Here is a sample of my pseudo code =
display "Would you like to add a link (y = yes or n = no)? "
input addLink
switch (link)
case 'y':
display "Would you like to pay 3 months in advance " + "(y = yes or n = no)?"
input advancePay
switch(advPay)
case 'y':
linkCost = 0.10 * (3 * 14.95)
case 'n'
linkCost = 14.95
case 'n'
linkCost = 0.00
Yes, but don't. If you need a further level of logic like that, place the second Switch in its own method with a descriptive name.
EDIT: By the example you've added, you've got two Boolean conditions. I would recommend against using switch at all, using if & else conditionals instead. Use (STRING.charAt(0) == 'y') as your test case, or something methodical like boolean isY(final String STRING) { return (STRING.charAt(0) == 'y' || STRING.charAt(0) == 'Y'); }
Yes. Switches break the language block statement pattern, but this is mainly because of C/C++ from which the switch statement used by Java is based.
In all three languages, the switch statement takes the following form:
switch(variable) {
case n:
statement 1;
statement n;
(optional) break;
case n+1:
statement 1;
statement n;
(optional) break;
// Optionally more statements
(optional) default:
statement 1;
statement n;
}
Because a switch statement breaks the traditional language pattern, many programmers wrap their multiple statements in a case using the traditional block style: { }
This is because most constructs in all three languages allow block style statements to be considered as one statement, but the switch statement does not require block style to execute multiple statements in a single case.
Without the break statement separating each case, there will be "fall through" - if case n was matched and did not have a break, the code under it (case n + 1) would be executed - if case n + 1 did not have a break and was matched, the default code would execute, if neither had a break, when matching case n, the code for case n, case n+1 and default would be executed.
The default is optional, and specifies a default action for a switch statement to execute. Typically, the default condition is either a generic handler, or a good place to throw an exception if the value could not logically be any other than the values in the switch statement.
To illustrate a switch statement executing inside a switch statement, take a look at this contrived example:
String message = null;
int outerVariable = getOuterVariable();
switch(outerVariable) {
case n:
statement 1;
statement n;
break;
case n+1:
int innerVariable = getInnerVariable();
switch(innerVariable) {
case 1:
message = "IT WAS 1";
break;
default:
message = "WHY WOULD YOU DO THIS? OH THE HUMANITY!";
}
break;
// Optionally more statements
(optional) default:
statement 1;
statement n;
}
It is possible, but that would be very convoluted and hard to read. There's almost certainly a better way, such as calling a method within the first switch statement and doing any more necessary processing (including another switch if necessary) in that method.
Most programming languages are orthogonal. That means, using a feature usually does not depend on the location, if meaningful.
For example, you cannot declare a local variable as public.