java Unit-1
java Unit-1
Unit-1
1.Encapsulation
2.Inheritance:
3.Polymorphism:
4.Abstraction:
5.Modularity and Reusability:
6.Message Passing:
OOM has been instrumental in shaping the development of software systems, from
desktop applications to web services and beyond. Many modern programming
languages, such as Java, C++, Python, and C#, are designed with OOM principles in mind
Advantages and Disadvantages of Procedure Oriented Languages:
Procedural Oriented Languages are programming languages that follow a procedural
paradigm, where the program's logic is organized into a series of procedures or functions.
The procedural paradigm focuses on executing a sequence of steps to achieve a desired
outcome. Here are some advantages and disadvantages of using procedural oriented
languages:
Advantages:
1. Simplicity: Procedural languages are often simpler and easier to learn for
beginners. They typically have a straightforward control flow that involves
executing statements in a linear fashion.
2. Efficiency: Procedural languages tend to be more efficient in terms of memory
usage and execution speed compared to some other programming paradigms,
especially in scenarios where tight control over hardware resources is required.
3. Clear Control Flow: The step-by-step nature of procedural programming makes it
easy to understand the flow of execution. This can be advantageous for programs
that follow a linear sequence of operations.
4. Resource Management: Procedural languages provide more direct control over
memory and resources, allowing developers to manage memory allocation and
deallocation more efficiently.
5. Legacy Systems: Many older systems and applications were built using procedural
languages like C and Pascal. Therefore, understanding procedural programming is
essential for maintaining and updating these legacy systems.
Disadvantages:
1. Limited Abstraction: Procedural languages often lack the level of abstraction
provided by object-oriented or functional languages. This can make it harder to
model complex real-world systems.
2. Code Maintenance: As programs grow in size and complexity, maintaining
procedural code can become challenging. Adding new features or making changes
may require modifying multiple parts of the codebase.
3. Code Reusability: Procedural languages may not promote code reusability as
effectively as other paradigms like object-oriented programming. Functions in
procedural languages can often be tightly coupled to specific tasks.
4. Scalability: Scaling up procedural programs can be cumbersome due to the lack of
modular structure inherent in object-oriented languages. Changes in one part of
the code might lead to unintended consequences in other parts.
5. Readability: As procedural programs become more intricate, their linear structure
can result in code that's harder to read and understand, especially if proper
documentation is lacking.
6. Difficulty in Modeling Real-World Relationships: Procedural programming might
struggle when it comes to modeling complex relationships between entities, as the
emphasis is on procedures rather than objects and their interactions.
7. Lack of Support for Parallelism: Many modern applications require parallelism or
concurrency for optimal performance. Procedural languages might not have built-
in mechanisms to handle this efficiently.
So, the object oriented development encouraged the software developers to develop
and work on the models of the application before implementing them. A model is an
abstraction of the software, which show what the software will do after final
implementation. So, it becomes easy to identify the flaws and manipulate them at the
time of implementation
Object Oriented Methodology:
The object oriented development process encourages the graphical representation of
the object oriented concept. So, before the software developers start building an
application, they build a model of it.
The model is then analyzed to discover the inadequacy and details are added to it during
implementation. The object oriented methodology is seamless from analysis to design
to implementation. This is because the information that is appended at one stage need
not be lost at the next stage.
Object Oriented Themes:
In Object-Oriented Programming (OOP), "object-oriented themes" refer to recurring
principles, patterns, and concepts that guide the design and development of software
using the object-oriented paradigm. These themes provide a structured approach to
creating modular, maintainable, and efficient code. Here are some key object-oriented
themes:
1. Abstraction:
Focus on Essential Details: Abstract away unnecessary complexities to provide a
clear and simplified representation of real-world entities and their interactions.
Use of Abstract Classes and Interfaces: Define abstract classes and interfaces to
provide common structure and behavior, promoting code reusability and
consistent interfaces.
2. Encapsulation:
Data Hiding: Hide the internal details of objects from outside access, allowing
controlled access to object data through well-defined methods.
Information Hiding: Restrict access to the inner workings of objects, preventing
external code from relying on implementation details.
3. Inheritance and Composition:
Code Reuse: Leverage inheritance to create new classes by extending existing ones,
inheriting their attributes and methods.
Favor Composition over Inheritance: Use composition to build complex objects by
combining simpler objects, allowing for more flexible relationships and modular
design.
4. Polymorphism:
Method Overriding: Override methods in subclasses to provide specialized
implementations while maintaining a common method signature.
Dynamic Binding: Enable dynamic method resolution at runtime, allowing different
objects to respond to method calls in a context-appropriate way.
5. Modularity:
Divide and Conquer: Break down a complex system into smaller, manageable
modules (classes), each responsible for a specific task or functionality.
High Cohesion and Low Coupling: Strive for high cohesion within modules and low
coupling between modules, promoting independence and maintainability.
6. Design Patterns:
Reusable Solutions: Apply well-established design patterns to common software
design problems, enhancing code quality and maintainability.
Examples: Singleton, Factory, Observer, Strategy, Adapter, Composite, and more.
By applying these object-oriented themes, developers can create software systems that
are flexible, modular, and closely aligned with real-world concepts, leading to more
efficient development and higher-quality code.
Benefits and Application of OOPS:
Object-Oriented Programming (OOP) offers a wide range of benefits and has applications
across various domains in software development. Here are the key benefits and
applications of OOP:
Benefits:
1. Modularity and Reusability: OOP encourages the creation of modular code by
organizing it into classes and objects. These modules can be reused across different
parts of an application or in different projects, leading to reduced development
time and improved efficiency.
2. Code Organization: OOP promotes a more organized and structured approach to
coding. Classes encapsulate data and methods related to a specific entity, making
the codebase easier to manage, understand, and maintain.
3. Abstraction: Abstraction allows developers to model real-world entities and
concepts by defining their essential characteristics while hiding unnecessary
details. This results in more intuitive and readable code.
4. Encapsulation: Encapsulation ensures that the internal details of an object's
implementation are hidden from external code. This protects the integrity of the
data and allows controlled access through well-defined interfaces.
5. Inheritance: Inheritance enables code reuse by allowing new classes to inherit
properties and behaviors from existing classes. This promotes a hierarchical
organization of classes and encourages the creation of specialized classes from
general ones.
6. Polymorphism: Polymorphism enables the same method or interface to be used
for different data types, promoting flexibility and adaptability in software design. It
simplifies code maintenance and enhances extensibility.
7. Ease of Maintenance: OOP's modular and structured nature makes it easier to
locate and fix bugs or make updates to specific parts of the code without affecting
other areas.
8. Collaborative Development: OOP supports collaborative development by allowing
developers to work on different classes and objects concurrently without
interfering with each other's work.
9. Scalability: OOP provides a foundation for building scalable applications. As the
codebase grows, OOP principles make it easier to manage complexity and extend
functionality.
Applications:
1. Software Development: OOP is widely used in building various types of software
applications, including desktop applications, web applications, mobile apps, and
more.
2. Game Development: OOP is particularly useful in game development, where
objects can represent game characters, items, environments, and interactive
elements.
3. Graphic User Interfaces (GUIs): OOP is well-suited for creating GUIs due to its
ability to model and manage visual components as objects.
4. Database Management Systems: OOP can be applied to develop database
applications, where objects can represent database connections, queries, and data
entities.
5. Simulation and Modeling: OOP can be used to model and simulate complex
systems, such as physics simulations, financial models, and scientific experiments.
6. Embedded Systems: OOP principles can be applied to develop software for
embedded systems, where objects represent hardware components and their
interactions.
7. Web Development: While the web development landscape has evolved to include
more functional and modular approaches, OOP can still play a role in backend
development and complex application architecture.
8. Artificial Intelligence and Machine Learning: OOP can be applied in building
software for AI and ML applications, where objects can represent algorithms,
models, and data structures.
9. Business Applications: OOP is suitable for building business applications like
enterprise resource planning (ERP) systems, customer relationship management
(CRM) systems, and more.
Principles of OOPS:
OOPS Paradigm:
OOP is an approach to program organization and development, which attempts to
eliminate some of the drawbacks of conventional programming methods by
incorporating the best of structured programming features with several new
concepts.
OOP allows us to decompose a problem into number of entities called objects and
then build data and methods (functions) around these entities.
The data of an object can be accessed only by the methods associated with the
object.
Some of the Object-Oriented Paradigm are:
Emphasis is on data rather than procedure.
Programs are divided into objects.
Data Structures are designed such that they Characterize the objects.
Methods that operate on the data of an object are tied together in the data
structure.
Data is hidden and can not be accessed by external functions.
Objects may communicate with each other through methods.
Abstraction
Abstraction can be defined as hiding internal implementation and showing only the
required features or set of services that are offered. This is the most essential part of
Object-Oriented programming. For example, people do not think of a car as a set of tens
of thousands of individual parts. They think of it as a well-defined object with its own
unique behavior. This abstraction allows people to use a car to drive to the grocery store
without being overwhelmed by the complexity of the individual parts. They can ignore
the details of how the engine, transmission, and braking systems work. Instead, they are
free to utilize the object as a whole.
Encapsulation
Encapsulation is the mechanism that binds together code and the data it manipulates,
and keeps both safe from outside interference and misuse. One way to think about
encapsulation is as a protective wrapper that prevents the code and data from being
arbitrarily accessed by other code defined outside the wrapper. Access to the code and
data inside the wrapper is tightly controlled through a well-defined interface.
Inheritance
Inheritance is the process by which one object acquires the properties of another object.
This is important because it supports the concept of hierarchical classification. The idea
behind inheritance is that you can create new classes that are built upon existing classes.
When you inherit from an existing class, you can reuse methods and fields of the parent
class. Moreover, you can add new methods and fields in your current class also. which is
also known as a parent-child relationship.
Dynamic Binding:
In dynamic binding, the code to be executed in response to the function call is decided at
runtime. Dynamic binding means that the code associated with a given procedure call is
not known until the time of the call at run time. Dynamic Method Binding One of the main
advantages of inheritance. This feature is known as subtype polymorphism.
Message Passing:
It is a form of communication used in object-oriented programming as well as parallel
programming. Objects communicate with one another by sending and receiving
information to each other. A message for an object is a request for execution of a
procedure and therefore will invoke a function in the receiving object that generates the
desired results. Message passing involves specifying the name of the object, the name of
the function, and the information to be sent.
Object oriented thinking:
A way of viewing world – Agents:
OOP uses an approach of treating a real world agent as an object.
Object-oriented programming organizes a program around its data (that is,
objects) and a set of well-defined interfaces to that data.
An object-oriented program can be characterized as data controlling access to
code by switching the controlling entity to data.
Responsibility:
primary motivation is the need for a platform-independent (that is, architecture-
neutral) language that could be used to create software to be embedded in various
consumer electronic devices, such as microwave ovens and remote controls.
Objects with clear responsibilities
Each class should have a clear responsibility.
If you can't state the purpose of a class in a single, clear sentence, then perhaps
your class structure needs some thought.
Messages:
In oops, Message passing is a way for objects to communicate with in a program. One
object can send a message to another object with specific data. Then other objects
performs the requested action based on the information provided in the message.
Methods:
A method is a group of instructions that is given a name and can be called up at
any point in a program simply by quoting that name.
Drawing a Triangle require draw of three straight lines. This instruction three times
to draw a simple triangle.
We can define a method to call this instruction three times and draw the
triangle(i.e. create a method drawLine( ) to draw lines and this method is called
repeatedly to achieve the needed task)
The idea of methods appears in all programming languages, although sometimes
it goes under the name functions and sometimes under the name procedures.
The name methods is a throw-back to the language C++, from which Java was
developed.
In C++, there is an object called a class which can contain methods. However,
everything in Java is enclosed within a class .so the functions within it are called
methods
Classes and instances:
Class:
Class is blue print or an idea of an Object
From One class any number of Instances can be created
It is an encapsulation of attributes and methods
syntax of CLASS:
class <ClassName>
{
attributes/variables;
Constructors();
methods();
}
Instance:
Instance is an Object of a class which is an entity with its own attribute values and
methods.
Creating an Instance:
ClassName refVariable;
refVariable = new Constructor();
or
ClassName refVariable = new Constructor();
class hierarchies:
The class hierarchy is tree like. In fact, not only is the hierarchy tree-like, Java provides a
universal superclass called Object that is defined to be the root of the entire class
hierarchy. Every class that is defined in a Java program implicitly extends the class Object.
Inheritance
Inheritance allows to reuse classes by deriving a new class from an existing one
The existing class is called the parent class, or superclass, or base class
The derived class is called the child class or subclass.
The child class inherits characteristics of the parent class (i.e the child class inherits
the methods and data defined for the parent class
Inheritance relationships are often shown graphically in a class diagram, with the
arrow pointing to the parent class
EX:
Consider two classes: Computer and Laptop
• A laptop is a kind of computer: therefore, a subclass
Method binding:
The Objects are used to call methods.
Method Binding is an object that can be used to call an arbitrary public method,
on an instance that is acquired by evaluatng the leading portion of a method
binding expression via a value binding.
It is legal for a class to have two or more methods with the same name.
Java has to be able to uniquely associate the invocation of a method with its
definition relying on the number and types of arguments.
Therefore the same-named methods must be distinguished:
by the number of arguments, or
by the types of arguments
Overloading and inheritance are two ways to implement polymorphism
Method Overriding:
There may be some occasions when we want an object to respond to the same
method but have different behaviour when that method is called.
That means, we should override the method defined in the superclass. This is
possible by defining a method in a sub class that has the same name, same
arguments and same return type as a method in the superclass.
Then when that method is called, the method defined in the sub class is invoked
and executed instead of the one in the superclass. This is known as overriding.
Exceptions:
Exception is an abnormal condition that arises in the code sequence.
Exceptions occur during compile time or run time.
“throwable” is the super class in exception hierarchy.
Compile time errors occurs due to incorrect syntax.
Run-time errors happen when
User enters incorrect input
Resource is not available (ex. file)
Logic error (bug) that was not fixed
Exception classes
In Java, exceptions are objects. When you throw an exception, you throw an
object. You can't throw just any object as an exception, however -- only those
objects whose classes descend from Throwable.
Throwable serves as the base class for an entire family of classes, declared in
java.lang, that your program can instantiate and throw.
Throwable has two direct subclasses, Exception and Error.
Exceptions are thrown to signal abnormal conditions that can often be handled by
some catcher, though it's possible they may not be caught and therefore could
result in a dead thread.
Errors are usually thrown for more serious problems, such as OutOfMemoryError,
that may not be so easy to handle. In general, code you write should throw only
exceptions, not errors.
Errors are usually thrown by the methods of the Java API, or by the Java virtual
machine itself.
History of Java:
Java was conceived by James Gosling, Patrick Naughton, Chris Warth, Ed Frank, and Mike
Sheridan at Sun Microsystems, Inc. in 1991. It took 18 months to develop the first working
version. This language was initially called “Oak,” but was renamed “Java” in 1995.
Between the initial implementation of Oak in the fall of 1992 and the public
announcement of Java in the spring of 1995, many more people contributed to the design
and evolution of the language. Bill Joy, Arthur van Hoff, Jonathan Payne, Frank Yellin, and
Tim Lindholm were key contributors to the maturing of the original prototype.
The primary motivation was the need for a platform-independent (that is, architecture-
neutral) language that could be used to create software to be embedded in various
consumer electronic devices, such as microwave ovens and remote controls.
The trouble with C and C++ (and most other languages at the time) is that they are
designed to be compiled for a specific target. Although it is possible to compile a C++
program for just about any type of CPU, to do so requires a full C++ compiler targeted for
that CPU. The problem is that compilers are expensive and time consuming to create. An
easier—and more cost-efficient—solution was needed. In an attempt to find such a
solution, Gosling and others began work on a portable, platform-independent
It provides many features that make the program execute reliably in a variety of
environments.
Java is a strictly typed language. It checks code both at compile time and runtime.
Java compilers can detect many problems that would first show up at execution
time in other languages
Java takes care of all memory management problems with garbage collection.
Java, with the help of exception handling, captures all types of serious errors and
eliminates any risk of crashing the system.
Secure
Java implements several security mechanisms to protect your system against harm
caused by stray programs.
Architecture Neutral
Java language and Java Virtual Machine helped in achieving the goal of “write once;
run anywhere, any time, forever.”
Changes and upgrades in operating systems, processors and system resources will
not force any changes in Java Programs.
Portable
Java is portable because of the Java Virtual Machine (JVM). The JVM is an abstract
computing machine that provides a runtime environment for Java programs to
execute.
The JVM provides a consistent environment for Java programs to run on,
regardless of the underlying hardware and operating system. This means that a
Java program can be written on one device and run on any other device with a JVM
installed, without any changes or modifications.
High Performance
Java performance is high because of the use of bytecode.
the Java bytecode was carefully designed so that it would be easy to translate
directly into native machine code for very high performance by using a just-in-time
compiler.
Multithreaded
Java was designed to meet the real-world requirement of creating interactive, networked
programs. To accomplish this, Java supports multithreaded programming, which allows
you to write programs that do many things simultaneously.
Dynamic
Java programs carry with them substantial amounts of run-time type information that is
used to verify and resolve accesses to objects at run time. This makes it possible to
dynamically link code in a safe and expedient manner. This is crucial to the robustness of
the Java environment, in which small fragments of bytecode may be dynamically updated
on a running system.
Data types:
byte
The smallest integer type is byte. This is a signed 8-bit type that has a range from –128 to
127. Variables of type byte are especially useful when you’re working with a stream of
data from a network or file
Byte variables are declared by use of the byte keyword. For example, the following
declares two byte variables called b and c:
byte b, c;
short
short is a signed 16-bit type. It has a range from –32,768 to 32,767. It is probably the least
used Java type. Here are some examples of short variable declarations:
short s;
short t;
int
The most commonly used integer type is int. It is a signed 32-bit type that has a range
from
–2,147,483,648 to 2,147,483,647. In addition to other uses, variables of type int are
commonly employed to control loops and to index arrays. Although you might think that
using a byte or short would be more efficient than using an int in situations in which the
larger range of an int is not needed, this may not be the case. The reason is that when
byte and short values are used in an expression, they are promoted to int when the
expression is evaluated. (Type promotion is described later in this chapter.) Therefore, int
is often the best choice when an integer is needed
long
long is a signed 64-bit type and is useful for those occasions where an int type is not large
enough to hold the desired value. The range of a long is quite large. This makes it useful
when big, whole numbers are needed. For example,
long days;
long seconds;
Floating-Point Types
Floating-point numbers, also known as real numbers, are used when evaluating
expressions that require fractional precision. For example, calculations such as square
root, or transcendentals such as sine and cosine, result in a value whose precision requires
a floating point type.
There are two kinds of floating-point types, float and double, which represent single- and
double-precision numbers, respectively. Their width and ranges are shown here:
float
The type float specifies a single-precision value that uses 32 bits of storage. Single
precision is faster on some processors and takes half as much space as double precision,
but will become imprecise when the values are either very large or very small. Variables
of type float are useful when you need a fractional component, but don’t require a large
degree of precision. For example, float can be useful when representing dollars and cents.
Here are some example float variable declarations:
float hightemp, lowtemp;
double
Double precision, as denoted by the double keyword, uses 64 bits to store a value. Double
precision is actually faster than single precision on some modern processors that have
been optimized for high-speed mathematical calculations. All transcendental math
functions, such as sin( ), cos( ), and sqrt( ), return double values. When you need to
maintain accuracy over many iterative calculations, or are manipulating large-valued
numbers, double is the best choice.
double pi, r, a;
Characters
In Java, the data type used to store characters is char. A key point to understand is that
Java uses Unicode to represent characters. Unicode defines a fully international character
set that can represent all of the characters found in all human languages.
At the time of Java’s creation, Unicode required 16 bits. Thus, in Java char is a 16-bit type.
The range of a char is 0 to 65,535. There are no negative chars. The standard set of
characters known as ASCII still ranges from 0 to 127 as always, and the extended 8-bit
character set, ISO-Latin-1, ranges from 0 to 255.
char ch1, ch2;
ch1 = 88; // code for X
ch2 = 'Y';
boolean
Java has a primitive type, called boolean, for logical values. It can have only one of two
possible values, true or false. This is the type returned by all relational operators, as in the
case of a < b. boolean is also the type required by the conditional expressions that govern
the control statements such as if and for.
boolean b;
b = false;
Variables:
The variable is the basic unit of storage in a Java program. A variable is defined by the
combination of an identifier, a type, and an optional initializer.
Declaring a Variable
In Java, all variables must be declared before they can be used. The basic form of a
variable
declaration is shown here:
type identifier [ = value ][, identifier [= value ] …];
Here, type is one of Java’s atomic types, or the name of a class or interface.The identifier
is the name of the variable. You can initialize the variable by specifying an equal sign and
a value. Keep in mind that the initialization expression must result in a value of the same
(or compatible) type as that specified for the variable. To declare more than one variable
of the specified type, use a comma-separated list.
Here are several examples of variable declarations of various types. Note that some
include an initialization.
Dynamic Initialization
Although the preceding examples have used only constants as initializers, Java allows
variables to be initialized dynamically, using any expression valid at the time the variable
is declared.
For example, here is a short program that computes the length of the hypotenuse of a
right triangle given the lengths of its two opposing sides:
// Demonstrate dynamic initialization.
class DynInit {
public static void main(String[] args) {
double a = 3.0, b = 4.0;
// c is dynamically initialized
double c = Math.sqrt(a * a + b * b);
System.out.println("Hypotenuse is " + c);
}
}
Here, three local variables—a, b, and c—are declared. The first two, a and b, are initialized
by constants. However, c is initialized dynamically to the length of the hypotenuse (using
the Pythagorean theorem). The program uses another of Java’s built-in methods, sqrt( ),
which is a member of the Math class, to compute the square root of its argument.
The following program demonstrates some type conversions that require casts:
// Demonstrate casts.
class Conversion {
public static void main(String args[]) {
byte b;
int i = 257;
double d = 323.142;
System.out.println("\nConversion of int to byte.");
b = (byte) i;
System.out.println("i and b " + i + " " + b);
System.out.println("\nConversion of double to int.");
i = (int) d;
System.out.println("d and i " + d + " " + i);
System.out.println("\nConversion of double to byte.");
b = (byte) d;
System.out.println("d and b " + d + " " + b);
}
}
The following program numbers each element in the array from left to right, top to
bottom, and then displays these values:
// Demonstrate a two-dimensional array.
class TwoDArray {
public static void main(String[] args) {
int[][] twoD= new int[4][5];
int i, j, k = 0;
for(i=0; i<4; i++)
for(j=0; j<5; j++) {
twoD[i][j] = k;
k++;
}
for(i=0; i<4; i++) {
for(j=0; j<5; j++)
System.out.print(twoD[i][j] + " ");
System.out.println();
}
}
}
When you allocate memory for a multidimensional array, you need only specify the
memory for the first (leftmost) dimension. You can allocate the remaining dimensions
separately.
For example, this following code allocates memory for the first dimension of twoD when
it is declared. It allocates the second dimension separately.
int[][] twoD = new int[4][];
twoD[0] = new int[5];
twoD[1] = new int[5];
twoD[2] = new int[5];
twoD[3] = new int[5];
While there is no advantage to individually allocating the second dimension arrays in this
situation, there may be in others.
For example, the following program creates a two-dimensional array in which the sizes of
the second dimension are unequal:
// Manually allocate differing size second dimensions.
class TwoDAgain {
public static void main(String[] args) {
int[][] twoD = new int[4][];
twoD[0] = new int[1];
twoD[1] = new int[2];
twoD[2] = new int[3];
twoD[3] = new int[4];
int i, j, k = 0;
for(i=0; i<4; i++)
for(j=0; j<i+1; j++) {
twoD[i][j] = k;
k++;
}
for(i=0; i<4; i++) {
for(j=0; j<i+1; j++)
System.out.print(twoD[i][j] + " ");
System.out.println();
}
}
}
The use of uneven (or irregular) multidimensional arrays may not be appropriate for many
applications, because it runs contrary to what people expect to find when a
multidimensional array is encountered. However, irregular arrays can be used effectively
in some situations.
Operators:
Java provides a rich operator environment. Most of its operators can be divided into the
following four groups: arithmetic, bitwise, relational, and logical. Java also defines some
additional operators that handle certain special situations.
Arithmetic Operators
Arithmetic operators are used in mathematical expressions in the same way that they are
used in algebra.
The following table lists the arithmetic operators:
The operands of the arithmetic operators must be of a numeric type. You cannot use them
on boolean types, but you can use them on char types, since the char type in Java is,
essentially, a subset of int.
The Basic Arithmetic Operators
The basic arithmetic operations—addition, subtraction, multiplication, and division—all
behave as you would expect for all numeric types. The unary minus operator negates its
single operand. The unary plus operator simply returns the value of its operand.
Remember that when the division operator is applied to an integer type, there will be no
fractional component attached to the result.
Java provides special operators that can be used to combine an arithmetic operation with
an assignment. As you probably know, statements like the following are quite common in
programming:
a = a + 4;
In Java, you can rewrite this statement as shown here:
a += 4;
This version uses the += compound assignment operator. Both statements perform the
same action: they increase the value of a by 4.
Here is another example,
a = a % 2;
which can be expressed as
a %= 2;
In this case, the %= obtains the remainder of a /2 and puts that result back into a. There
are compound assignment operators for all of the arithmetic, binary operators.
Thus, any statement of the form
var = var op expression;
can be rewritten as
var op= expression;
The outcome of these operations is a boolean value. The relational operators are most
frequently used in the expressions that control the if statement and the various loop
statements.
The Assignment Operator
You have been using the assignment operator since Chapter 2. Now it is time to take a
formal look at it. The assignment operator is the single equal sign, =. The assignment
operator works
in Java much as it does in any other computer language. It has this general form:
var = expression;
Here, the type of var must be compatible with the type of expression
int x, y, z;
x = y = z = 100; // set x, y, and z to 100
The ? Operator
Java includes a special ternary (three-way) operator that can replace certain types of if-
then-else statements. The ? has this general form: expression1 ? expression2 :
expression3 Here, expression1 can be any expression that evaluates to a boolean value.
If expression1 is true, then expression2 is evaluated; otherwise, expression3 is evaluated.
The result of the ? operation is that of the expression evaluated. Both expression2 and
expression3 are required to return the same (or compatible) type, which can’t be void.
Operator Precedence:
Table 4-1 shows the order of precedence for Java operators, from highest to lowest.
Operators in the same row are equal in precedence. In binary operations, the order of
evaluation is left to right (except for assignment, which evaluates right to left). Although
they are technically separators, the [ ], ( ), and . can also act like operators. In that capacity,
they would have the highest precedence. Also, notice the arrow operator (->). It is used
in lambda expressions.
Using Parentheses
Parentheses raise the precedence of the operations that are inside them. This is often
necessary to obtain the result you desire. For example, consider the following expression:
a+b/3 // compute b/3 first and adds result to ‘a’
(a+b)/3 // compute a+b first and result can divisible by 3
Control Statements:
A programming language uses control statements to cause the flow of execution to
advance and branch based on changes to the state of a program. Java’s program control
statements can be put into the following categories: selection, iteration, and jump.
if
The if statement is Java’s conditional branch statement. It can be used to route program
execution through two different paths.
Here is the general form of the if statement:
if (condition) statement1;
else statement2;
Here, if a is less than b, then a is set to zero. Otherwise, b is set to zero. In no case are
they both set to zero.
Nested ifs
A nested if is an if statement that is the target of another if or else. Nested ifs are very
common in programming. When you nest ifs, the main thing to remember is that an else
statement always refers to the nearest if statement that is within the same block as the
else and that is not already associated with an else. Here is an example:
if(i == 10) {
if(j < 20) a = b;
if(k > 100) c = d; // this if is
else a = c; // associated with this else
}
else a = d; // this else refers to if(i == 10)
The if-else-if Ladder
A common programming construct that is based upon a sequence of nested ifs is the if-
elseif ladder. It looks like this:
if(condition)
statement;
else if(condition)
statement;
else if(condition)
statement;
.
.
.
else
statement;
The if statements are executed from the top down. As soon as one of the conditions
controlling the if is true, the statement associated with that if is executed, and the rest of
the ladder is bypassed. If none of the conditions is true, then the final else statement will
be executed. The final else acts as a default condition; that is, if all other conditional tests
fail, then the last else statement is performed. If there is no final else and all other
conditions are false, then no action will take place.
// Demonstrate if-else-if statements.
class IfElse {
public static void main(String[] args) {
int month = 4; // April
String season;
if(month == 12 || month == 1 || month == 2)
season = "Winter";
else if(month == 3 || month == 4 || month == 5)
season = "Spring";
else if(month == 6 || month == 7 || month == 8)
season = "Summer";
else if(month == 9 || month == 10 || month == 11)
season = "Autumn";
else
season = "Bogus Month";
System.out.println("April is in the " + season + ".");
}
}
Here, the traditional form of the switch is examined. Here is the general form of a
traditional switch statement:
switch (expression) {
case value1:
// statement sequence
break;
case value2:
// statement sequence
break;
.
.
.
For versions of Java prior to JDK 7, expression must resolve to type byte, short, int, char,
or an enumeration. Today, expression can also be of type String. Each value specified in
the case statements must be a unique constant expression (such as a literal value).
Duplicate case values are not allowed. The type of each value must be compatible with
the type of expression.
The traditional switch statement works like this: The value of the expression is compared
with each of the values in the case statements. If a match is found, the code sequence
following that case statement is executed. If none of the constants matches the value of
the expression, then the default statement is executed. However, the default statement
is optional. If no case matches and no default is present, then no further action is taken.
The break statement is used inside the switch to terminate a statement sequence. When
a break statement is encountered, execution branches to the first line of code that follows
the entire switch statement. This has the effect of “jumping out” of the switch.
The break statement is optional. If you omit the break, execution will continue on into
the next case. It is sometimes desirable to have multiple cases without break statements
between them. For example, consider the following program:
// In a switch, break statements are optional.
class MissingBreak {
public static void main(String[] args) {
for(int i=0; i<12; i++)
switch(i) {
case 0:
case 1:
case 2:
case 3:
case 4:
System.out.println("i is less than 5");
break;
case 5:
case 6:
case 7:
case 8:
case 9:
System.out.println("i is less than 10");
break;
default:
System.out.println("i is 10 or more");
}
}
}
This program generates the following output:
i is less than 5
i is less than 5
i is less than 5
i is less than 5
i is less than 5
i is less than 10
i is less than 10
i is less than 10
i is less than 10
i is less than 10
i is 10 or more
i is 10 or more
As you can see, execution falls through each case until a break statement (or the end of
the switch) is reached.
Nested switch Statements
You can use a switch as part of the statement sequence of an outer switch. This is called
a nested switch. Since a switch statement defines its own block, no conflicts arise
between the case constants in the inner switch and those in the outer switch. For
example,
switch(count) {
case 1:
switch(target) { // nested switch
case 0:
System.out.println("target is zero");
break;
case 1: // no conflicts with outer switch
System.out.println("target is one");
break;
}
break;
case 2: // ...
Here, the case 1: statement in the inner switch does not conflict with the case 1:
statement in the outer switch. The count variable is compared only with the list of cases
at the outer level. If count is 1, then target is compared with the inner list cases.
Iteration Statements:
Java’s iteration statements are for, while, and do-while. These statements create what
we commonly call loops.
while
The while loop is Java’s most fundamental loop statement. It repeats a statement or block
while its controlling expression is true. Here is its general form:
while(condition) {
// body of loop
}
The condition can be any Boolean expression. The body of the loop will be executed as
long as the conditional expression is true. When condition becomes false, control passes
to the next line of code immediately following the loop. The curly braces are unnecessary
if only a single statement is being repeated.
The body of the while (or any other of Java’s loops) can be empty. This is because a null
statement (one that consists only of a semicolon) is syntactically valid in Java. For
example,
This program finds the midpoint between i and j. It generates the following output:
Midpoint is 150
do while
The do-while loop always executes its body at least once, because its conditional
expression is at the bottom of the loop. Its general form is
do {
// body of loop
} while (condition);
Each iteration of the do-while loop first executes the body of the loop and then evaluates
the conditional expression. If this expression is true, the loop will repeat. Otherwise, the
loop terminates. As with all of Java’s loops, condition must be a Boolean expression.
Jump Statements
Java supports three jump statements: break, continue, and return. These statements
transfer control to another part of your program.
Using break
In Java, the break statement has three uses. First, as you have seen, it terminates a
statement sequence in a switch statement. Second, it can be used to exit a loop. Third, it
can be used as a “civilized” form of goto.
Using continue
Sometimes it is useful to force an early iteration of a loop. That is, you might want to
continue running the loop but stop processing the remainder of the code in its body for
this particular iteration. The continue statement performs such an action. In while and
do-while loops, a continue statement causes control to be transferred directly to the
conditional expression that controls the loop.
// Demonstrate continue.
class Continue {
public static void main(String[] args) {
for(int i=0; i<10; i++) {
System.out.print(i + " ");
if (i%2 == 0) continue;
System.out.println(" ");
}
}
}
This code uses the % operator to check if i is even. If it is, the loop continues without
printing a newline. Here is the output from this program:
01
23
45
67
89
return
The last control statement is return. The return statement is used to explicitly return from
a method. That is, it causes program control to transfer back to the caller of the method.
As such, it is categorized as a jump statement.
At any time in a method, the return statement can be used to cause execution to branch
back to the caller of the method. Thus, the return statement immediately terminates the
method in which it is executed.
// Demonstrate return.
class Return {
public static void main(String[] args) {
boolean t = true;
System.out.println("Before the return.");
if(t) return; // return to caller
System.out.println("This won't execute.");
}
}
As you can see, the final println( ) statement is not executed. As soon as return is
executed, control passes back to the caller.