final and other Java keywords - 1

"Hi, Amigo!"

"Hi, Bilaabo!"

"Today I'm going to tell you about several keywords in Java. But I'll start with the most interesting: the keyword final."

"You can use the keyword final when declaring a variable, method, or class."

"And why do we need final?"

"It's pretty simple. If we mark a variable as final, then it becomes unchangeable:"

final int i = 5;
i++; //Compilation error: the value of i cannot be changed.

"I see."

"If we mark a method as final, then overriding the method in derived classes is forbidden:"

class Cat
{
 public final String getName()
 {
  return "cat";
 }
}

class Tiger extends Cat
{
 public String getName() //Compilation error: overriding the getName()
 {
  return "tiger";
 }
}

"I see. But why would you need to prohibit overriding a method?"

"Well, as an example, suppose a programmer has written a lot of important code in a method and wants to guarantee that all classes that inherit his class will have the specified behavior."

"And finally, the third usage."

"If we mark a class with the keyword final, then it cannot be inherited."

public final class Cat
{
 public String getName()
 {
  return "cat";
 }
}

class Tiger extends Cat //Compilation error: the Cat class cannot be
{
 public String getName()
 {
  return "tiger";
 }
}

"And why would we prevent a class from being inherited?"

"You should understand that we don't prevent inheritance to be annoying, but rather for the sake of security and code integrity. If class inheritance is not prohibited, then the implication is that it is allowed. And that the code written by the class's designer will work properly for objects of this class as well as objects of any derived classes."

"But if a developer realizes that even small changes to his class will cause everything to stop working as expected, then it is better to forbid inheritance."

"For example, the String class is declared as final, as are all primitive types: Integer, Boolean, Double, Character…"

"Ah, got it. The String class was created as an immutable class and if they were suddenly mutable, then a lot of things would stop working."

"Well, almost. Let's put it this way: everything would work almost as before, but sometimes there would be errors that would be very difficult to find and understand. So, in some cases, inheriting classes or methods is not really a sin, but forbidding it means fewer errors to catch later."

"Where else can you use final?"

"You can use final before function parameters, and before variables in a method. Here's an example:"

public void setName(final String name)
{
 final String displayName = "Mr."+ name;
  …
 this.name = displayName;
}

"And what's the point of that?"

"Well, there are two. First, we declare a variable as final if we want to tell other developers that this value is a specific constant, and not just a variable."

For example, we want to calculate the sales tax based on a price:

public int getPriceNDS()
{
 final int NDS = 20;
 return this.price * NDS / 200;
}

"And second, we need this type of variable when writing local or anonymous inner classes. I'll tell you about these types of classes soon. But not today."

"Okay, so far there hasn't been anything too complicated."

"Please note that only the variable becomes unchangeable, not an object it might refer to. The object can still be changed."

"I was actually just about to ask about that. And there's no way to make the object unchangeable?"

"No, unless you write an immutable class."

"Please note that because the value of a final variable can't be changed, you must assign its initial value immediately."

This code will compile This code won't compile
class Home
{
 private final int width = 200;
 private final int height = 100;

 public Home()
 {
 }
}
class Home
{
 private final int width;
 private final int height;

 public Home()
 {
 }
}

"But, that said, Java lets you delay initialization of a class's final variables until the constructor."

This code will compile This code won't compile
class Home
{
 private final int width = 200;
 private final int height;

 public Home()
 {
  height = 100;
 }
}
class Home
{
 private final int width;
 private final int height;

 public Home()
 {
  height = 100;
 }
}

"Additionally, different constructors can initialize final variables with different values. This is quite convenient:"

This code will compile
class Home
{
 private final int width;
 private final int height;

 public Home()
 {
  height = 100;
  width = 200;
 }

 public Home(int width)
 {
  this.height = 300;
  this.width = width;
 }

 public Home(int width, int height)
 {
  this.height = height;
  this.width = width;
 }
}

"That was a really interesting topic, and absolutely everything makes sense. Thank you, Bilaabo!"