Instructor: Instead, let's talk about switch
with record patents.
This is a new feature introduced in Java 21.
And this allows direct record deconstruction,
and this results in more concise and readable code.
What does this allow you to do?
Over here, we have a interface called customer message
and we have two implementations, message and feedback.
And what we are doing in here is switching on instance
of the CustomerMessage.
And our cases are two implementations of those interfaces,
message and feedback.
So, we are saying if the type of this object is this,
then we would want to do this.
If the type of this object is this,
then we would want to do this.
So, what we are checking is the specific implementation
of this interface and based on that,
we are writing a switch case.
Isn't this awesome?
Let's explore this further right now.
I've already created
a class called SwitchRecordsRunner,
com.in28minutes.api.f is the package
and we have a empty SwitchRecordsRunner class in here.
In here, what we want to do,
is we would want to start with defining a simple interface.
So, we have an interface called CustomerMessage.
For now let's not really make it complex,
let's not have any methods in this.
Let's just have a simple interface
and we would want to have a record called, Message.
Inside Message, we would want to have a String text,
and this would implement the CustomerMessage interface.
Nice.
And we would want to create another record implementing
the CustomerMessage interface as well.
Let's call this feedback.
So, we would have a,
int rating
and a String description.
Looks good?
So, we have one interface,
two implementations of those interfaces,
and we are ready to get our switch magic rolling.
Let's first create a simple CustomerMessage.
So, CustomerMessage,
message is equal to, we can create either of them,
let's just say for enough new message of hello,
and we would want to switch on this.
So, switch on the message.
The interesting thing is you can switch
on the type of CustomerMessage.
Let's define a case in here.
If it's the type message, then let's keep it simple for now.
Let's just declare a variable in here, message,
and let's return back a value.
We will get return message.text,
we'll return it as it is.
Actually we should call the method.
So, what are we doing in here?
We want to create a switch expression.
So, let's actually say String response is equal to this.
Nice, isn't it?
So, you can see that over here we have duplicate thing,
CustomerMessage and message,
the variable names are the same.
So, let's call this customerMessage
and let's switch over customerMessage.
And over here we are writing message.text.
Let's put a semicolon at the end of the switch.
Now you'd see an error.
It says, what does it say?
Switch expression should have a default case.
So, what it's saying
is there is a chance that it's not this.
Okay, let's go ahead and see what is the other thing?
Let's say if fits feedback.
If it's feedback, and let's call this feedback
and let's say feedback.description.
Does this make this happy?
Nope.
This also does not make it happy.
Why is it asking for default?
Right now the CustomerMessage
has two implementations, message and feedback.
But there's a chance that at a later point in time
you might add more implementations.
That's why the compiler is not happy.
It's saying, hey, I know that right now
you have only two implementations,
but still I want a default.
There might be a implementation somewhere outside as well.
I might know about it only at runtime.
So, it's forcing you to say default,
return back a default value.
If you do a sysout,
and print out the response,
what do you would see?
What do you expect to see?
You'd see, hello?
The message being printed, right?
If this was something else,
if let's say I was creating a feedback object.
Let's call this Feedback
and let's say the Feedback is five
and really good, right?
So, let's say this is the CustomerMessage.
Then if you run it,
you'd see the feedback.description coming back.
So, over here, this is the interface
and based on the implementation of this interface,
we are able to return different values
from your switch expression.
Now what if I would want to eliminate the default?
Let's say I don't want to have the default in here.
I just want to remove default.
You can do that if the interface was sealed.
I can say this is a sealed interface.
Earlier we looked at sealed interfaces,
and we'll say permits Message,
Feedback.
Once you do this, does the compiler become happy?
You can see that the compiler becomes happy.
Why?
Because by default, all record classes are final.
So, you can explicitly put final in here,
but even by default record classes are final.
So, the compiler is now happy.
It's also not complaining about the default in here.
Because now, it knows this CustomerMessage interface
can only be implemented by message and feedback.
And we have covered both the cases in here.
So, isn't this cool?
Now we can take this to one step deeper,
over here, we can also do the destruction.
So, instead of creating a message object,
I can directly destruct it to the text.
So, inside message we have text.
So, I can say String text in here
and directly return the text back.
You can do the same thing for feedback as well.
So, I can take this, and replace this,
and now I directly have the description.
If you run this, we are sending a feedback,
we are creating a feedback object.
And so it's printing really good,
it's printing the description.
So, what we are looking at is an example
of switch with record patterns.
We are switching on a reference object of the type interface
and our cases are based on the implementations
of that interface.
And we were also able to do record deconstruction.
We were able to directly map
the rating and the description
to the specific variables in here.
The thing is, you can also do it with nested records.
So, let's take this one step deeper with nested records.
Let's say, on top of this,
we would want to create another record.
So, record SupportRequest.
So, SupportRequest contains a String username
and it contains the CustomerMessage message.
So, we are defining a new record in here,
and now we want to actually switch on the new record object.
So, what I'll do is I'll go to the end here
and let's actually create an object of the SupportRequest.
So, let's say SupportRequest.
Request is equal to new SupportRequest
of a username.
Let's say it's Rahul,
and we can pass the same feedback in,
new feedback of five, really good.
So, you can create the SupportRequest
with either the feedback
or you can also use the message.
Why?
Because the support request is made of a String
and a CustomerMessage.
So, you can pass in any of the implementations
of the CustomerMessage.
So, you can create instances of any of the implementations,
message or feedback and send it out here.
And you can easily switch around this request as well.
So, here, let's make sure
that the entire piece of code is visible.
Okay, this looks pretty good.
Now what we want to do is to do a switch around this.
So, we want to create a String
and,
let's call this responseMessage.
We already have available with the name response in here.
So, I'm just calling this responseMessage,
and we want to switch
on request.
Nice.
What does the error say?
Switch expression
should have at least one result expression.
We will do that.
Let's add a semicolon first
and let's add a case.
So, case,
if it's SupportRequest,
and inside the SupportRequest,
let's do the destruction as well.
String.
So, what does the support request contain?
String user and CustomerMessage message.
So, String user,
the next thing could be CustomerMessage.
And let's call this message.
If this is the case, let's return,
user back.
Let's keep it simple for now.
In case if it's SupportRequest,
let's get
user,
what's the other possibility,
if it's not CustomerMessage?
It can be feedback.
Feedback, feedback.
And let's return back, feedback in here.
Let's actually put CustomerMessage in here.
So, we are writing CustomerMessage,
and over here we are writing Feedback, right?
So, this looks simple.
Let's add a semicolon.
It's saying the case label is being dominated
by an earlier one,
because I'm putting CustomerMessage in here.
Actually it should not be CustomerMessage.
I would need to put in a type of a CustomerMessage,
which should be message.
So, let's put it message.
So, I'm checking.
So, what we are doing
is we are looking at the SupportRequest,
and if the support request is of the type message,
we want to do this.
So, we want to return message back.
If it's of the type Feedback, we want written Feedback.
Let's actually run this quickly,
and let's do a sysout of responseMessage.
What would be printed?
So, you can see that feedback is being printed.
We created a Feedback SupportRequest.
Now look at what the switch is doing.
It's looking at the SupportRequest.
And,
if the SupportRequest is of the type Message,
if SupportRequest contains Message,
then it's executing a specific case statement.
If it contains Feedback, it's executing another statement.
You can take it one level deeper as well.
So, over here you can also say,
I want to distract the Message directly.
And you can say Message of String text.
And even feedback, you can replace it with int rating,
String description.
The code here might look really complex,
but once you get used to the structure,
you will see that this is very, very easy to understand.
So, what we are defining
is this structure of SupportRequest.
So, if it's a SupportRequest containing message, do this.
If it's SupportRequest containing Feedback,
then this is the case which needs to be executed.
So, now you have access to the text.
So, we can send the text back,
over here, we can send the description back.
And now you'd see when you execute it,
so, it says really good, really good
because the Feedback object,
which is being sent in here says really good.
Now I if I change it to Message.
So, over here I'm changing this to Message,
and sending it this, and sending it in,
and running this.
Nice, spending, Hello.
So, what we are seeing in here
is nested record patterns in switch.
This supports automatic deconstruction of records.
It works seamlessly with nested records.
In this step, we looked at switch with record patterns
and nested record patterns.
Switch statement has evolved considerably
over the last few Java versions.
Pattern matching with switch was a great enhancement.
Switch expressions was a great enhancement.
And now, nested record patterns in switch
is another awesome enhancement.
I'll recommend you to play further with this example
and I'll see you in the next step.