User Professor Hans Noodles
Professor Hans Noodles
Level 41

Fixed values in Java: final, constants, and immutable

Published in the Java Developer group
Hi! You're already familiar with the word "modifier". At a minimum, you've encountered access modifiers (public, private) and the static modifier.
Fixed values in Java: final, constants, and immutable - 1
Today we'll discuss a special modifier called final. You could say the final modifier "cements" parts of our program where constant, unambiguous, unchanging behaviors are needed. There are three places in your programs that you can use it: classes, methods, and variables. Fixed values in Java: final, constants, and immutable - 2 Let's run through them in order. If the final modifier is used in a class declaration, it means the class can't be inherited. In previous lessons, we used a simple inheritance example: we had an Animal parent class and two child classes: Cat and Dog

public class Animal {
}



public class Cat extends Animal {
   // Fields and methods of the Cat class
}


public class Dog extends Animal {

   // Fields and methods of the Dog class
}
However, if we use the final modifier on the Animal class, the Cat and Dog classes cannot inherit it.

public final class Animal {

}

public class Cat extends Animal {

   // Error! Cannot inherit from final Animal
}
The compiler immediately generates an error. In Java, many final classes are already implemented. Among those you use frequently, String is the most well-known. Moreover, if a class is declared as final, all of the class's methods also become final. What does that mean? If a method is declared using the final modifier, you can't override that method. For example, here we have an Animal class that declares a speak() method. But, dogs and cats definitely "speak" in different ways. So, we'll declare speak() methods in both the Cat and Dog classes, but we'll implement them differently.

public class Animal {
  
   public void speak() {
       System.out.println("Hello!");
   }
}

public class Cat extends Animal {

   @Override
   public void speak() {
       System.out.println("Meow!");
   }
}

public class Dog extends Animal {

   @Override
   public void speak() {
       System.out.println("Woof!");
   }
}
We made the Cat and Dog classes override the method declared in the parent class. Now, an animal will speak differently, depending on what type of object it is:

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       Dog dog = new Dog();
      
       cat.speak();
       dog.speak();
   }
}
Output: Meow! Woof! However, if we declare the Animal class's speak() method as final, then we can't override it in other classes:

public class Animal {

   public final void speak() {
       System.out.println("Hello!");
   }
}


public class Cat extends Animal {

   @Override
   public void speak() {// Error! A final method can't be overridden!
       System.out.println("Meow!");
   }
}
And our objects will be forced to use the speak() method as defined in the parent class:

public static void main(String[] args) {

   Cat cat = new Cat();
   Dog dog = new Dog();

   cat.speak();
   dog.speak();
}
Output: Hello! Hello! Now, regarding final variables. They are also known as constants. First (and most importantly), the initial value assigned to a constant value can't be changed. It is assigned once and for all.

public class Main {
  
   private static final int CONSTANT_EXAMPLE = 333;

   public static void main(String[] args) {

       CONSTANT_EXAMPLE = 999;// Error! You can't assign a new value to a final variable!
   }
}
A constant doesn't need to be initialized immediately. That can be done later. But, the value initially assigned to it will stay the same forever.

public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;// This is allowed
}
Second, note our variable's name. Java has a different naming convention for constants. It isn't the usual camelCase notation. If it had been an ordinary variable, we would have called it constantExample. But, the names of constants are written in all caps, with underscores between words (if there is more than one word), e.g. "CONSTANT_EXAMPLE". Why do we need constants? They are very useful if, for example, there is a fixed value you regularly use in a program. For example, you've decided to make history and write the game "The Witcher 4" by yourself. The game will obviously regularly use the protagonist's name: "Geralt of Rivia". This string (and other heroes' names) is best declared as a constant: its value will be stored in one place, and you definitely won't make a typo when entering it a million times.

public class TheWitcher4 {

   private static final String GERALT_NAME = "Geralt of Rivia";
   private static final String YENNEFER_NAME = "Yennefer of Wengerberg";
   private static final String TRISS_NAME = "Triss Merigold";

   public static void main(String[] args) {

       System.out.println("The Witcher 4");
       System.out.println("It's already the fourth Witcher game, but " + GERALT_NAME + " still can't decide who" +
               " he likes more: " + YENNEFER_NAME + " or " + TRISS_NAME);

       System.out.println("But, if you've never played The Witcher before, we'll start from the beginning.");
       System.out.println("The protagonist's name is " + GERALT_NAME);
       System.out.println(GERALT_NAME + " is a witcher, a monster hunter");
   }
}
Output: The Witcher 4 It's already the fourth Witcher game, but Geralt of Rivia still can't decide who he likes more: Yennefer of Wengerberg or Triss Merigold But, if you've never played The Witcher before, we'll start from the beginning. The protagonist's name is Geralt of Rivia Geralt of Rivia is a witcher, a monster hunter We've declared the heroes' names as constants. Now we definitely won't make a typo, and there's no need to write them out by hand each time. Another plus: if we ever need to change the variable's value across the entire program, you can do it in one place, rather than manually modifying it across the entire code base. :)

Immutable types

As you've worked with Java, you've probably already gotten used to the idea that programmers have almost complete control over the state of all objects. If you want to create a Cat object, you can. If you want to rename it, you can. If you want to change its age or something else, you can. But Java has several data types that have a special property. They are immutable. If a class is immutable, then the state of its objects can't be changed. Want some examples? It might surprise you, but the most well-known immutable class is String! So, we really can't change a String's value? Well, let's try it:

public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   str1 = "I love Python";// but changing str1 has no impact on str2
   System.out.println(str2);// str2 continues to point to the "I love Java" string, but str1 now points to a different object
}
Output: I love Java I love Java After we wrote

str1 = "I love Python";
the "I love Java" string object didn't change or go anywhere. It still happily exists and has the exact same text as before. The code

str1 = "I love Python";
simply created another object, which str1 now points to. But, we can't seem to have any effect on the "I love Java" string object. Okay, let's try something else! The String class is full of methods, and some of them appear to change the object's state! For example, there's a replace() method. Let's change the word "Java" to "Python" in our string!

public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   str1.replace("Java", "Python");// We try to change the state of str1 by swapping the word "Java" with "Python"
   System.out.println(str2);
}
Output: I love Java I love Java It didn't work again! Maybe the replace method doesn't work? Let's try something else. For example, substring(). It returns a substring based on character indices passed as arguments. Let's cut off the first 10 characters of our string:

public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   str1.substring(10);// Truncate the original String 
   System.out.println(str2);
}
Output: I love Java I love Java Fixed values in Java: final, constants, and immutable - 3 Nothing changed. And it shouldn't have. Like we said earlier, Strings are immutable. So, what's with all the methods in the String class? After all, they can truncate strings, change characters, and more. What's the point if nothing happens? They actually can do these things! But, they return a new String every time. It's pointless to write

str1.replace("Java", "Python");
because you can't change the original object. But, if you write the method's result to a new reference variable, you'll see the difference immediately!

public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   String str1AfterReplacement =  str1.replace("Java", "Python");
   System.out.println(str2);

   System.out.println(str1AfterReplacement);
}
All String methods work this way. Nothing can be done to the "I love Java" object. You can just create a new object and write: "<new object> = the result of manipulating the "I love Java" object ". What other types are immutable? Some that you'll definitely need to remember right away are all the wrapper classes for the primitive types. Integer, Byte, Character, Short, Boolean, Long, Double, Float: all of these classes create immutable objects (we'll talk about them in upcoming lessons). This includes classes used to create large numbers, such as BigInteger and BigDecimal. We recently covered exceptions and touched on the stack trace. Well, guess what, java.lang.StackTraceElement objects are also immutable. This makes sense: if someone could change our stack's data, it would make the whole thing pointless. Imagine someone going through the stack trace and changing an OutOfMemoryError to a FileNotFoundException. And then you use that stack to find the cause of the error. But the program doesn't even use files. :) So, they made these objects immutable, just in case. Okay, so it more or less make sense for StackTraceElement. But, why would anyone need to make Strings immutable? Why would changing their values be a problem? It would probably even be more convenient. :/ There are several reasons for this. First, it saves memory. Immutable strings can be placed in the string pool, allowing strings to be reused instead of creating new ones. Second, for security. For example, usernames and passwords are Strings in almost every program. Making possible to change them could result in authorization problems. There are other reasons, but our study of Java hasn't covered them yet, so we'll come back to them later.
Comments (20)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
John H Level 15, Charlotte, United States
26 April 2021
When str1 is assigned, it's given a specific memory location. When str2 is assigned str1's string, then str2 now points to the same memory location as str1. The string in that location cannot be changed. Assigning a different string to str1 causes the java virtual machine to assign this new string to a different memory location or 'string pool'. str2 still points to the original location and thus prints the original string.
lokesh singla Level 15, San Jose, United States
4 December 2020
So looks like we cant change the values of the final variables. And if we want to get the same experience for objects as well we need to make their data type i.e. class immutable. By making the object as final variable we cant change the reference to which that variable is pointing, but we can change the values that are there for that reference. By making data type i.e. class as immutable, we won't be able to change the value as well for that reference. I hope my understanding is correct.
Kou Shikyo Level 20, Tokyo
3 October 2020
I love Geralt of Rivia , I love Yennefer of Wengerberg ,I love witcher 3. !!!
Pighost Level 16, Warszawa, Poland
27 August 2020
I have problem with that : String str1 = "I love Java"; String str2 = str1; System.out.println(str2); str1 = "I love Python"; System.out.println(str2); Why would u print str2 to show me that the class is immutable if u changing value of str1? Correct me please if I'm wrong but when u changed str1, you should print str1 also and it shouldn't be changed. I think I understund the idea of creating new String object each time it is assigned but I cant understund this printing of str2.
Ryan Level 16, Ashburn, United States
25 June 2020
I am trying to understand the difference between final and immutable and I think the issue may be this sentence for a constant " the value initially assigned to it will stay the same forever." I searched the web and found this explanation that seems to contradict this sentence: As a side note: Variables that are declared final and are mutable can still be changed; however, the variable can never point at a different object. The explanation with the additional code showing a constant being change can be found here: https://stackoverflow.com/questions/66066/what-is-the-best-way-to-implement-constants-in-java I want to understand the difference between final and constant but I am not sure when I would use one over the other.
Peter Schrijver Level 23, Hilversum, Netherlands
11 June 2020
Clear. ;o)
Austeja Level 10, Kaunas, Lithuania
22 May 2020
I love the picture when the man is holding his head.
FullMet Level 29, Kyiv, Ukraine
27 March 2020
Like for the Witcher) Toss the coin to the witcher...
Johannes Level 27, Centurion, Pretoria, South-Africa
18 March 2020
Your explanation makes no sense, sorry ;) You are modifying the created string (s1), but printing a previous created copy (s2), so if you were printing the original string, it will show it was modified. So not really getting how that's "immutable", but will read up on it.
Kent Hervey Level 16, United States
17 March 2020
Using Eclipse and debugging I did a sample programming showing how object IDs change when a String seems to be changing...really it is being added