Comprehending Java’s Data Types
Understanding and correctly utilizing data types enables developers to enhance the efficiency of their code as each data type requires specific resources. Additionally, specifying a particular data type prevents the compilation of code if you attempt to store a different type, such as by accident. Consequently, statically typed languages enable the detection of errors even before conducting any testing.
Java offers two types of data: primitive and reference (also called non-primitive). Through this tutorial, you will utilize variables to store and employ data in a Java program, thereby gaining knowledge about frequently employed data types in Java. While not covering every single data type, this guide will assist you in acquainting yourself with the available options in Java.
Requirements
In order to proceed with this tutorial, the things you will require are:
- An environment in which you can execute Java programs to follow along with the examples. To set this up on your local machine, you will need the following:Java (version 11 or above) installed on your machine, with the compiler provided by the Java Development Kit (JDK). For Ubuntu and Debian, follow the steps for Option 1 in our tutorial, How To Install Java with Apt on Ubuntu 22.04. For other operating systems, including Mac and Windows, see the download options for Java installation.
To compile and run the code examples, this tutorial uses Java Shell, a Read-Evaluate-Print Loop (REPL) run from the command line. To get started with JShell, check out the Introduction to JShell guide. - Familiarity with Java and object-oriented programming, which you can find in our tutorial, How To Write Your First Program in Java.
Basic types.
Java primitive types are the most fundamental and basic data types in Java, representing raw values like numbers and characters. Commonly used primitive data types include int for integers, boolean for boolean values, and char for characters. Additional primitive types can be explored through the official Java data types documentation.
Whole numbers
Integers encompass both negative and positive whole numbers. In Java, you will employ the data type int to hold them. The int type is capable of handling sufficiently large numbers for most applications, ranging from -2,147,483,648 to 2,147,483,647.
Now, let us examine the usage of int in an illustrative case:
int theAnswer = 42;
In Java, primitive types should begin with a lowercase letter (e.g., int). According to Java’s syntax rules, you need to first declare the data type (int) and then provide its name (theAnswer). Following that, you assign a value of 42 to the variable using the equals sign (=).
You can use a variable in Java by simply mentioning its name without adding any special characters, regardless of its data type, as Java can identify it as a variable.
Note
After the variable is declared, you can access and utilize it within a method by referencing it in the following manner:
int theAnswer = 42;
System.out.println("The answer to all questions is " + theAnswer);
To test if a variable is declared correctly, you can utilize the println method from the System.out package to print theAnswer onto the console. This approach is the most straightforward.
To witness the functioning of this code, utilize the Java Shell tool. Once you have Java installed, open a terminal or command prompt on your own computer and input jshell.
- jshell
Your result will have a resemblance to the following:
| Welcome to JShell — Version 11.0.16 | For an introduction type: /help intro jshell>
After completing the console tasks, you can copy the code snippets provided in this tutorial. To exit jshell, simply type /exit.
To initiate and utilize the integer variable, copy and insert the subsequent lines into the jshell console:
- int theAnswer = 42;
- System.out.println(“The answer to all questions is “ + theAnswer);
You will observe the subsequent outcome.
theAnswer ==> 42 The answer to all questions is 42
This result verifies that you have accurately assigned the value of 42 to the int variable theAnswer. Furthermore, you have effectively utilized theAnswer by passing it to a function, which has generated the expected outcome for the variable.
A native paraphrase for “Boolean” could be “true or false condition” or “logical variable.”
Boolean values can only be true or false, and in Java, you would utilize the boolean data type to store them. For instance, we can create a boolean variable to determine if Java is enjoyable or not.
boolean isJavaFun = true;
You set the variable isJavaFun to true. The opposite boolean value is false.
By utilizing the aforementioned variable, you can display the sentence “Java is fun: true” in the following manner:
- boolean isJavaFun = true;
- System.out.println(“Java is fun: “ + isJavaFun);
If you run these lines in jshell, you will see the following output.
isJavaFun ==> true Java is fun: true
Just like the int example, the println method will display the argument enclosed in the parentheses. By using the plus sign (+), the string “Java is fun: ” will be combined with the variable isJavaFun, resulting in a single argument: the string “Java is fun: true”.
Characters in a story or play.
You can utilize the char data type to store a single alphanumeric character, as shown by the following example:
char firstLetter = 'a';
Observe that the letter ‘a’ is enclosed by single quotation marks. Single quotes are exclusively used for char values, whereas double quotes are employed for strings, as you will discover later.
The char type may not appear very useful since having a variable assigned to a single character is unlikely to be necessary. Nonetheless, char is essential in creating character string classes like String, which essentially consist of a collection of char values.
Primitive type variables in this section are easy to declare and use since they represent simple values like integers. These values can be used immediately without any additional steps like creating objects or invoking methods.
Types of references
In the initial lesson of this series, named “How To Create Your Initial Java Program,” you gained knowledge about the organization of Java code in classes, which serve as blueprints for creating objects. By assigning objects to variables, you essentially indicate or make reference to those objects. In such instances, these variables are categorized as reference types. Unlike primitive type variables, which are unable to refer to objects, these non-primitive variables are capable of doing so.
Reference type variables are crucial in Java and object-oriented programming in general because they allow access and utilization of objects that possess advanced properties and can actively perform actions through their triggered methods. Without these variables pointing to objects, their potential power remains untapped, rendering them practically unusable.
Note
Reference types, unlike primitive types, have virtually limitless possibilities as there is no restriction on the number of classes (and interfaces). Each class represents a reference type. Java has numerous pre-existing classes that offer crucial features, most of which can be found in the core java.lang package. This section will provide an overview of some commonly utilized ones.
The Class of Strings.
The String class is used to represent a sequence of characters that form a string. To declare a String variable, or any other reference type variable, you need to specify its type and give it a name. Then, you can assign a value to it using the equals sign. This process is similar to working with primitive types. However, unlike primitive types, reference types refer to objects, so you need to create an object if one doesn’t already exist. Here is an example:
String hello = new String("Hello");
The variable “hello” is a String with a reference type. When you assign a new String object to it, you use the “new” keyword along with the class name, which in this case is “String”. It is worth mentioning that the class “String” always begins with a capital letter. According to convention, all classes and reference types should start with a capital letter.
Every class possesses a unique function known as a constructor, which is utilized to generate fresh objects. By appending parentheses (()) after the class name, you can activate this constructor. The constructor can also receive arguments, as demonstrated in the aforementioned example, where the parameter “Hello” is passed to the String constructor.
To verify that the hello variable functions as intended, reiterate it as an argument for the println method in the following manner:
- String hello = new String(“Hello”);
- System.out.println(hello);
When these lines are executed in jshell, the output will be as follows.
hello ==> “Hello” Hello
This time, the result shows that the variable hello is assigned as Hello. Following that, the same Hello is displayed on a separate line, verifying that the println() function has executed it.
The indigenous option for paraphrasing “Wrapper Classes” is “Class Wrappers.”
In the preceding section, you dealt with the String reference type, which is commonly utilized. There are other well-liked reference types known as wrappers for primitive types. These wrapper classes encapsulate or hold primitive data, and that’s why they are called wrappers. All primitive types have their corresponding wrapper counterparts, and presented below are a few illustrations:
- Integer: To wrap int values.
- Character: To wrap char values.
- Boolean: To wrap boolean values.
The reason for the presence of these wrappers is to enable the enhancement of a basic primitive value into a robust object. Every wrapper contains pre-built functions specific to the values it is intended to hold.
For instance, you will examine the class Integer. In the previous section, you initialized a String object using the new keyword. Nonetheless, certain classes offer and even prefer the utilization of specific methods to obtain objects from them, and Integer is among those classes. With Integer, employing a special method mainly focuses on optimizing resources, but in other cases, it may aim to streamline the creation of intricate objects.
In this example, you initialize an Integer variable named theAnswer to 42 by using the valueOf method.
- Integer theAnswer = Integer.valueOf(42);
- System.out.println(theAnswer);
When using jshell, the output provided will be as follows.
theAnswer ==> 42 42
When you use the Integer method valueOf(42) in Java, you are asking it to provide you with an object that holds this specific value. Java will then check if it already has an object with the same value in its cache. If it does, the variable theAnswer will be linked to that object. If not, a new object will be created for the variable theAnswer.
For the sake of performance, several pre-existing classes offer such methods, and it is advised, if not required, to utilize them. While using the new keyword is still possible for Integer, it will generate a warning message indicating its deprecated nature.
Besides String and wrappers, the java.lang package summary includes various other beneficial built-in reference types. A comprehensive understanding of these advanced reference types may necessitate further explanation or prior knowledge. Consequently, we will explore some of them in our future Java tutorials.
Word-for-word/verbatim translations
Literals are values that are fixed and can be directly used in the code, and therefore can be assigned to both primitive and reference types. There are several types of literals that can be classified as follows.
Primitive type literals
In the section about primitive types, you have already utilized several literals. Each primitive type has its own literal representation, like the ones we showed in our examples: 42, ‘a’, and true. When it comes to integers, 42 is considered an integer literal. Likewise, ‘a’ represents a character literal, and true and false are boolean literals.
You can create values for reference types using primitive types literals as well. For instance, the int literal was utilized to create an Integer object with the code Integer.valueOf(42). Alternatively, you can directly assign the value in a simpler way like this:
Integer theAnswer = 42;
You can assign the integer value of 42 directly to the variable named theAnswer without any extra statements, as it is a whole number and considered as an integer literal. This method of declaring an integer is often used due to its convenience.
For instance, this abbreviated method is applicable to various primitive types literals and their corresponding reference types, such as Boolean.
Boolean isFun = true;
The isFun variable of type Boolean can be directly assigned the true literal. Similarly, the same assignment can be made using the false literal.
The literal string
There is a unique symbol for the String reference type, which is identified through the double quotation marks around its content. In this instance, it is expressed as “Hello, World!”.
String helloWorld = "Hello, World!";
Many programmers prefer to use literals because they are simpler and shorter. However, it is still possible to declare a String variable using a new String object, as demonstrated in the section on reference types.
The absence of value expressed in writing as the Null Literal.
One additional crucial literal is null, which signifies the lack of a value or the nonexistence of an object. Null enables the creation of a reference type that can be directed towards null instead of an object. While null can be employed with any reference types, it is not applicable to primitive types.
There is a limitation when using the null literal: it allows you to declare variables, but you cannot use these variables until you assign a suitable value that is not null. If you attempt to use a reference type variable with a null value, an error will occur. Here is an illustration:
- String initiallyNullString = null;
- System.out.println(“The class name is: “ + initiallyNullString.getClass());
If you attempt to execute this code in jshell, you will encounter an error that resembles the following.
initiallyNullString ==> null | Exception java.lang.NullPointerException | at (#4:1)
The output might vary depending on your operating system and the version of Java you are using.
The reason why the error java.lang.NullPointerException occurs is that you are attempting to call the getClass() method (which gives the class name) on the variable initiallyNullString (which refers to a null object).
Note
In order to fix the mistake, you need to assign a new value to the initiallyNullString like this:
- String initiallyNullString = null;
- initiallyNullString = “not null any longer”;
- System.out.println(“The class name is: “ + initiallyNullString.getClass());
The output that will be printed is as follows after the code has been fixed:
initiallyNullString ==> null initiallyNullString ==> “not null any longer” The class name is: class java.lang.String
The output above demonstrates the transition of initiallyNullString from being null to becoming a new String object with the content “not null any longer”. Subsequently, when the getClass() method is applied to the created object, the output is java.lang.String, where String represents the class name and java.lang denotes its package. Ultimately, a complete and informative message is displayed: “The class name is: class java.lang.String”.
Declaring a null value is often seen in older code. It involves creating a variable first and then later assigning its actual value, often through certain logic that determines it. However, Java version 8 introduced a new reference type called Optional, which is better suited for situations where null was previously used.
Inference of the type of local variables
You have been using common data types in Java to define variables up until now. But with the introduction of Java 10, a new feature called local variable type inference allows you to use the keyword var in front of a new variable. Using var, Java can automatically guess the data type from the local context. Type inference is a topic of dispute as it goes against the verbosity of defining variables, as explained earlier. The pros and cons of this feature are debatable, but other statically typed languages like C++ do support type inference.
Regardless, type inference is incapable of fully substituting the usage of data types as it solely applies to local variables, which are variables confined within a method. To illustrate this, let’s examine an instance involving the var keyword.
- var hello = “Hello”;
- System.out.println(hello);
To ensure Java recognizes the data type of the variable, you use the var keyword to declare the variable hello. Afterwards, you verify its functionality by printing it to the console in the customary manner.
hello ==> “Hello” Hello
As long as your Java installation, specifically the JDK, is above version 10, this example will function properly. The var keyword is not compatible with older versions.
During the compilation process, type inference occurs. This means that when you compile the code, the compiler turns the plain text source code into machine code and applies different optimizations, including type inference. Type inference guarantees that the appropriate amount of memory is allocated for variables with inferred types. Consequently, the machine code that is executed after compilation is fully optimized, as if you had manually specified all the data types.
The var keyword is functional in this instance because it pertains to a local variable. The var data type is exclusively applicable to local variables, which are declared within methods and can solely be accessed within those methods, hence their designation as “local”.
In order to demonstrate that the var keyword is restricted to local variables, attempt to position it outside of the main method, such as this:
- public class Hello {
- var hello = “Hello”;
- public static void main(String[] args) {
- // example code
- }
- }
If you paste the code mentioned above into jshell, you will encounter the error:
| Error: | ‘var’ is not allowed here | var hello = “Hello”; | ^-^
The use of “var” is prohibited in this case as “hello” is located outside of a method and therefore is no longer considered as a local variable. Consequently, type inference cannot function for non-local variables due to the unreliable availability of contextual information to determine the data type.
Although using var can be difficult and is not mandatory, it is likely to be encountered, making it beneficial to familiarize oneself with it.
Keywords that are reserved
When you declare variables in Java, it is important to be aware of one more crucial rule. There are specific keywords that are reserved and cannot be used as variable names. For instance, you cannot declare a primitive of the int type and give it the name “new” like this:
- int new = 1;
If you attempt this example, you will encounter compilation errors due to the reservation of the keyword “new”.
| Error: | ‘.class’ expected | int new = 1; | ^ | Error: | <identifier> expected | int new = 1; | ^ | Error: | ‘(‘ or ‘[‘ expected | int new = 1; | ^ | Error: | unexpected type | required: value | found: class | int new = 1; | ^–^ | Error: | missing return statement | int new = 1; | ^———-^
The new keyword is utilized to generate fresh objects, and Java does not anticipate it in this position. Among the errors listed in the previous output, the primary section holds the utmost significance.
| Error: | ‘.class’ expected | int new = 1; | ^
The ‘.class’ expected error occurs when the new keyword is used without a class following it. Java is unable to understand the statement and subsequent errors occur.
Other reserved keywords like abstract, continue, default, for, and break carry their own specific definitions in Java and cannot be employed as variable names. The entire compilation of reserved keywords can be located on the Java Language Keywords page. In case you can’t recall every reserved keyword, you can rely on compilation errors to identify the problem.
In summary, in conclusion.
In this lesson, you gained knowledge about basic and non-basic data types in Java, which is a challenging yet crucial subject. Dedicate ample time for practicing and reviewing the examples multiple times. Experiment with altering various data types and values. Observe when errors occur and when they don’t, to grasp the concept of successful code execution.
To learn more about Java, take a look at our How To Code in Java series.
More Tutorials
Addition Assignment Operator mean in Java(Opens in a new browser tab)
Converting a Python string to an integer and vice versa.(Opens in a new browser tab)
get pandas DataFrame from an API endpoint that lacks order?(Opens in a new browser tab)
Primefaces’ Message, Messages, and Growl components(Opens in a new browser tab)
The program in Java for displaying “Hello World”(Opens in a new browser tab)