Pattern Matching in IF clause?
It’s achieved using instanceof operator
If ( number instanceof Integer data) {
print(data.compareTo(5));
}
It reduces the boiler plate code of chcecking instanceof and then type casting to that instanceof operator. Now with this approach variable data is a typecasted reference to be used within block. Its scope is limited to its IF block only. Here the variable data is called pattern variable
Pattern variable and optional conditional clause?
Example:
If ( number instanceof Integer data && data >= 10) {
Print(“data=“+data);
}
It converts to pattern variable and also checks whether it’s more than or equal to 10 before proceeding.
What is the output ?
Number num=12;
If(num instanceof final Integer data){
data=12;
Print(data);
}
Doesn’t compile
Pattern variable is declared as final and can’t be assigned again.
Flow scoping
If(number instanceof Integer data || data.compareTo(5) > 0)
Print(data);
What is the output
Doesn’t compile
Compiler recognizes the risk that number may not be an integer in which case it tries to evaluate next expression and data.compareTo may not even work.
In pattern variable matching the comditions must be joined by conditional AND && operator
Scope of pattern variable
It depends on flow scoping and it’s not limited to if block itself. It can flow to next statement if compiler determines variable data type is made sure to be compatible with statements that follows
Number num=Integer.valueOf(5);
If( ! (num instanceof Integer data))
return;
Print (data);
Switch statement vs Switch expression?
Int num=4;
switch (num){
case 1:
Print(“tiger”); break;
case 2:
Print(“lion”); break;
default:
Print(“other”);
}
String animal= switch(num){
case 1 -> “tiger”;
case 2 -> “lion”;
default -> “other”;
};
Switch variable data types supported are…
byte and Byte
short and Short
int and Integer
char and Character
String
enum values
All object types (when used with pattern matching )
var (if it resolves to above)
Note: boolean, long, float and double are not supported.
Acceptable switch case values
Compile time Constants such as literals, enums, final constant variables
What is the output of switch?
Season s=Season.SPRING;
var p=switch(s){
case SUMMER -> “summer”;
case Season.FALL -> “fall”;
case Season.WINTER -> “winter”;
case s -> “spring”;
};
Print(p);
A) spring
B) null
C) doesn’t compile because default not present
D) doesn’t compile due to last case statement
(D)
Doesn’t compile because case value needs to be a literal expression and should not contain any variable including enum variable
Does switch expression statement requires break?
No
They don’t need to. They return one single expression evaluated value and doesn’t make sense to have break clause.
Can switch expression return different data types?
No
When used it throws a compile error. It should match with resulting datatype on left side of assignment operator
void identifyType(String type){
Integer reptile=switch(type){
case “snake” -> 1;
case “turtle” -> 2;
};
}
Doesn’t compile as there is no default clause.
Unlike switch statement, switch expression should either exhaust all scenarios or at least it should have a default clause. Otherwise compiler knows in case if switch value doesn’t match with any case value it would be a problem at run time.
How to exhaust a switch
1) add a default clause
2) if it’s enum, add all possible enum constants in case values
3) use pattern matching to cover all cases
Is it ok to add default clause in switch when case values cover all possible scenarios?
Yes
Though default would be unnecessary and it’s optional and dead code.
It’s recommended to add default clause all the time even if case values cover all just in case future programmer may add code that may evaluate to other possible scenarios such as adding a new enum constant to the enum
Why we need yield statement in switch
Sometimes switch expressions are not that simple to have a single statement to return value in each clause.
To solve this, we use code block {} to hold multiple statements but return only a single value using yield statement
Switch expression with exception thrown in a code block
In a switch expression every case should return value either through single expression or with yield in a code block unless an exception is thrown in a case.
Please note throw clause can be in a code block only
Int Len=3;
var name=switch(Len){
case 1 -> “fish”;
case 2 -> { yield “trout”;}
case 3 -> { throw new RuntimeException(); }
default -> “shark”;
};
Pattern Matching with Switch
You use it with object reference in switch variable and pattern matching in case clause.
The same rules about local variables and flow scoping apply here too. For instance the pattern matching variable exists only with in case branch.
Example:
Number h = Integer.valueOf(6);
String msg=switch(h){
case Integer i -> “Rounded:” + i;
case Double d -> “Precise:” + d;
case Number n -> “Unknown:” + n;
};
Pattern matching in switch expression combined with conditional clause
This is similar to IF clause when we use && and a relational expression that includes a pattern matching variable
The difference is instead of && we use when keyword
Example:
case Integer i when i > 10 -> “Venky”;
case Integer i -> “Amulya”;
You can have multiple case clauses with same pattern matching with different conditional clauses to separate them out. In above example Venky is returned only if integer is greater than 10. All other integer cases, Amulya is returned
What is the output?
Number animal = 10;
var msg=switch(animal){
case Integer i -> “Daniel”;
case Integer i when i > 10 -> “Venky”;
default -> “suresh”;
};
Print(msg);
Doesn’t compile
The 2nd case is never reachable in the event animal is an integer. Compiler knows and throws error.
Exhaustive Switch
Switch expressions should always be exhaustive irrespective of whether patttern matching is used or not
Switch statements doesn’t need to be exhaustive if pattern matching is not used. But they need to be when pattern matching is used
What is the output
Number zoo=Integer.valueOf(5);
switch(zoo){
case Integer c -> print(“hello”);
case Number n -> print(“Venky”);
default -> print(“awesome”);
}
Doesn’t compile
Though switch statement is exhausting the default is not necessary in this case because zoo is Number type and there is a case with Number already dominating the default so compile throws an error because default is not reachable at all
what if switch variable is null at runtime?
When switch variable is null at run time we get NullPointerException. The code compiles though as long as it’s exhaustive if used with pattern matching with switch statement or for any type of switch expression.
To avoid this runtime problem you route can use if clause to catch it or add a new case statement like below
case null:
Using case null in switch statement
Using case null is considered to be using pattern matching so it needs to be exhaustive. A simple way to do that is add default clause.
Order of case null and default?
when used both default should always be used after case null