Java Data Types and Instructions

In the last chapter we wrote programs with bare minimum knowledge of data types and instructions. As a result, the programs worked only for specific data. If they are to work with other data it would necessitate changes in the program, which is not a good idea. In this chapter we propose to rectify this situation. For that, we have to have more in depth knowledge of data types and instructions. There is a lot of ground to cover here. Let us begin with the data types.  

Data Types Revisited

So far we have used only an int to deal with integer values and float to deal with real values. However, Java provides many flavors of integers and reals. Let us begin with integers.  

Integer Types

Sure! Let’s dive deeper into each section to further explain Java’s data types and instructions.

Java supports four different types of integer data types, which vary in their size (number of bytes) and range (the minimum and maximum values they can hold):

  • byte (1 byte):
    • Range: -128 to 127
    • It is used when memory is a constraint or when we know the value will not exceed the small range, such as for storing binary data in files.
  • short (2 bytes):
    • Range: -32,768 to 32,767
    • short is useful in situations where memory is limited, and we want to use slightly larger integers than byte.
  • int (4 bytes) (default integer type):
    • Range: -2^31 to 2^31 – 1
    • Most commonly used integer data type in Java because it provides a wide range and is efficient on most hardware.
  • long (8 bytes):
    • Range: -2^63 to 2^63 – 1
    • long is used when we need very large integers beyond the range of int. For example, when dealing with big financial calculations or counting large numbers of items.

Key Rules for Integers:

By default, numbers without decimal points are treated as int.

  • Example:
int x = 1000; // treated as int
  • When assigning a value beyond the range of the data type, you get an error:
byte a = 300; // Error: 300 is beyond the range of byte (-128 to 127)
short b = 40000; // Error: 40000 exceeds short's limit (-32,768 to 32,767)

Using long integers:

  • When you want to declare a large integer, you should append an L (or l) to indicate that the value is of type long:
long x = 2200000000L; // correct

Improving Readability:

  • You can use underscores (_) between digits to make large numbers more readable. For example:
long creditCardNumber = 1211_5178_9212_4231L;

This doesn’t affect the value but improves human readability.

Real (Floating-Point) Types

Java supports two types of floating-point (real) numbers:

  • float (4 bytes):
    • Range: approximately ±3.40282347E+38F (6-7 decimal digits of precision).
    • Use float when memory usage is critical and you don’t need very high precision.
  • double (8 bytes) (default floating-point type):
    • Range: approximately ±1.79769313486231570E+308 (15-16 decimal digits of precision).
    • Use double when precision is important (e.g., for scientific calculations).
    • It is the default for real numbers in Java.

Important Considerations:

  • By default, any number with a decimal is treated as a double:
float x = 3.5; // Error: 3.5 is treated as double, but x is float
float y = 3.5f; // Correct: using 'f' to indicate float
double z = 3.5; // Correct: 3.5 is a double

Exponential Notation:

  • For very large or very small real numbers, it’s easier to use scientific/exponential notation:
float a = 3.41295e-5f; // 0.0000341295 in scientific notation
double b = 3.21e3;     // 3210.0 in scientific notation
  • Precision Issues:
    • Real numbers are stored in binary format, which can cause small precision errors during conversion from decimal to binary.
    • For example, 5.375 and 5.375f are not equal. When stored as a double (64 bits), 5.375 is more precise than when stored as a float (32 bits). This can lead to small errors in calculations where precision matters.

char Data Type

The char data type is used to represent single characters. Each char occupies 2 bytes of memory and is represented using Unicode.

  • Unicode can represent almost all written languages, unlike the older ASCII format, which was limited to 128 characters.

Ways to Declare a char:

  • Using a single character literal:
char letter = 'A';
  • Using Unicode notation:
char letter = '\u0041'; // Unicode for 'A'

Unicode values range from '\u0000' to '\uffff', representing decimal 0 to 65535.

boolean Data Type

The boolean data type represents logical values: true or false.

  • In Java, boolean is not an integer, unlike in some other languages (like C/C++), where true is often represented by 1 and false by 0. Java strictly uses true and false for boolean values.
  • A boolean variable can either be directly assigned a value (true or false) or be the result of an expression that evaluates to a boolean value:
boolean flag = true; // Direct assignment
boolean comparison = (4 > 2); // Result of a boolean expression

Example:

boolean isJavaFun = true;
System.out.println(isJavaFun); // Output: true

boolean isGreater = 5 > 3; 
System.out.println(isGreater); // Output: true

Receiving Input in Java

In Java, there are different ways to receive input from the user, including using the Scanner, InputStreamReader, and BufferedReader classes. Each has its unique characteristics and use cases. We’ll discuss two common methods: using Scanner and using InputStreamReader combined with BufferedReader.

Using InputStreamReader and BufferedReader

The following program demonstrates how to use these classes:

package sibyreceivinginput ;
import java.io.* ;
public class SiByReceivingInput
{
 public static void main ( String[ ] args ) throws Exception
 {
     float p, r, si;
     int n;
     InputStreamReader isr = new InputStreamReader(System.in);
     BufferedReader br = new BufferedReader(isr);
     
     System.out.println("Enter values of p, n and r:");
     p = Float.parseFloat(br.readLine()); // Reading float input
     n = Integer.parseInt(br.readLine());  // Reading integer input
     r = Float.parseFloat(br.readLine());  // Reading float input
     
     si = (p * n * r) / 100;
     System.out.println("Simple interest = Rs. " + si);
 }
}
Explanation:
  • Classes Used:
    • InputStreamReader reads bytes from the standard input stream (System.in) and converts them into characters.
    • BufferedReader wraps InputStreamReader to buffer the input, making input reading more efficient.
  • Data Conversion: Input is taken in string format using readLine() and converted to numeric types using parseFloat() and parseInt().

This method is useful when dealing with larger input as BufferedReader offers efficient buffering of input streams. One caveat is that you must handle the potential IOException thrown by BufferedReader.

Handling Exceptions

If incorrect input is provided (such as a non-numeric value when expecting an integer), the program throws an exception. To simplify, we use the throws Exception clause, though better exception handling practices can be applied, like using try-catch.

Command-Line Arguments

An alternative way to provide input to a Java program is through command-line arguments. These arguments are supplied when running the program and can be accessed in the main() method through the args array.

package siusingcmdlineargs;
public class SiUsingCmdLineArgs {
    public static void main(String[] args) {
        float p, r, si;
        int n;
        
        p = Float.parseFloat(args[0]);  // Getting the first argument as float
        n = Integer.parseInt(args[1]);  // Getting the second argument as int
        r = Float.parseFloat(args[2]);  // Getting the third argument as float
        
        si = (p * n * r) / 100;
        System.out.println("Simple interest = Rs. " + si);
    }
}
How to Use Command-Line Arguments:
  1. The values for p, n, and r are passed during the execution of the program in the terminal (or through IDE configurations).
  2. In NetBeans, for instance, you can set the command-line arguments in the project properties window.

Java Instructions

Java programs are composed of different types of instructions. In our case, we often encounter type declaration and arithmetic instructions.

Type Declaration

Each variable must be declared before use, specifying the type (e.g., int, float, char). You can also initialize variables during declaration:

int i = 10, j = 25;
float a = 1.5f, b = 1.99f;

Arithmetic Instructions in Java

In Java, arithmetic instructions refer to operations that involve basic mathematical calculations like addition, subtraction, multiplication, division, and modulus. These operations are essential in almost every program to manipulate data and perform computations. Let’s dive into each operation and understand how they work in Java.

1. Types of Arithmetic Operators

Java provides the following basic arithmetic operators:

OperatorSymbolDescription
Addition+Adds two operands
Subtraction-Subtracts the second operand from the first
Multiplication*Multiplies two operands
Division/Divides the first operand by the second
Modulus (Remainder)%Returns the remainder of division

These operators can be applied to numeric data types such as int, float, double, long, etc.

2. Examples of Arithmetic Operations

Here are some simple examples of arithmetic operations:

Addition (+)

int a = 10;
int b = 5;
int sum = a + b;  // sum = 15
  • This operation adds the values of a and b and stores the result in the sum variable.

Subtraction (-)

int x = 20;
int y = 8;
int difference = x - y;  // difference = 12
  • This operation subtracts y from x and stores the result in difference.

Multiplication (*)

int p = 7;
int q = 3;
int product = p * q;  // product = 21
  • Multiplication of p and q yields 21, which is stored in product.

Division (/)

int m = 15;
int n = 3;
int quotient = m / n;  // quotient = 5
  • Division of m by n results in a quotient of 5.

However, division behaves differently when dealing with integer and floating-point numbers:

  • When both operands are integers, integer division is performed, and the decimal part is truncated (not rounded).

Example:

int result = 7 / 2;  // result = 3, not 3.5

For precise division, use floating-point numbers:

float result = 7.0f / 2;  // result = 3.5

Modulus (%)

int dividend = 10;
int divisor = 3;
int remainder = dividend % divisor; // remainder = 1
  • The modulus operator returns the remainder of the division of dividend by divisor. This is particularly useful for determining whether a number is even or odd, or for circular operations (like finding positions in a cyclic structure).

Example:

int number = 7;
if (number % 2 == 0) {
System.out.println(number + " is even.");
} else {
System.out.println(number + " is odd.");
}

3. Arithmetic Expressions

An arithmetic expression can combine multiple arithmetic operations. Parentheses () can be used to group operations and control the order of evaluation. Java follows operator precedence rules, similar to regular mathematics.

Precedence and Associativity

The order in which operators are evaluated in an expression is determined by their precedence. Higher precedence operators are evaluated first. If two operators have the same precedence, their associativity (left-to-right or right-to-left) determines the order of evaluation.

OperatorPrecedenceAssociativity
*, /, %HighestLeft-to-right
+, -LowerLeft-to-right

For example:

int result = 5 + 3 * 2;  // result = 11 (multiplication is done first)

If we want addition first, we can use parentheses:

int result = (5 + 3) * 2;  // result = 16

More Complex Expressions

int result = 10 + 5 * 2 - 3 / 1;  // result = 17
  • Multiplication and division happen first, followed by addition and subtraction, based on operator precedence.
    • Step-by-step evaluation: 10 + 10 - 320 - 317.

4. Type Promotion in Arithmetic Expressions

When you combine different data types in an arithmetic operation, Java promotes smaller data types to larger ones to prevent data loss. For example, when an int is combined with a float, the int is promoted to a float before the operation.

Example:

int x = 7;
float y = 3.0f;
float result = x + y; // x is promoted to float, result = 10.0

Example of Type Promotion

int a = 5;
double b = 4.5;
double result = a + b; // result = 9.5 (int a is promoted to double)

5. Handling Division by Zero

  • Integer Division by Zero: If you try to divide an integer by zero, Java will throw an ArithmeticException.

Example:

int a = 5;
int b = 0;
int result = a / b; // Throws ArithmeticException: / by zero
  • Floating-point Division by Zero: Division by zero with floating-point numbers results in special values like Infinity or NaN (Not a Number).

Example:

float x = 5.0f;
float y = 0.0f;
float result = x / y; // result = Infinity

6. Compound Assignment Operators

Java provides compound assignment operators that simplify arithmetic operations. These operators perform an operation and assign the result in one step.

Compound OperatorExampleEquivalent to
+=a += ba = a + b
-=a -= ba = a - b
*=a *= ba = a * b
/=a /= ba = a / b
%=a %= ba = a % b

Example:

int x = 10;
x += 5; // Equivalent to: x = x + 5; x is now 15

7. Unary Operators

Unary operators work on a single operand. In arithmetic, the most common unary operators are the increment (++) and decrement (--) operators.

  • Increment Operator (++): Increases the value of a variable by 1.
  • Decrement Operator (--): Decreases the value of a variable by 1.

Example:

int i = 5;
i++; // i is now 6
--i; // i is now 5

There are two forms of these operators:

  1. Post-increment (i++): The variable is incremented after its value is used.
  2. Pre-increment (++i): The variable is incremented before its value is used.

Example:

int a = 5, b;
b = a++; // b = 5, a = 6 (post-increment)
b = ++a; // b = 7, a = 7 (pre-increment)