Ryan
Ryan
PROGRAMMING WITH
J AVA
Todo list
Preface 1
Why Write This Book? 1
To the Student 1
1 Introduction 3
What is Java? 3
Is Java a Good Language to Learn Programming? 3
Popularity 3
What is Java Good For? 5
What is Java not Good For? 5
Recap 5
Exercises 6
Engineering Lore: What is Engineering? 6
3 Hello, World! 15
A Short History of "Hello, World!" 15
The Java "Hello, World!" Program 15
Running the Program 17
Whitespace and Style 17
Comments 18
When to Comment, What to Comment? 18
Recap 19
Exercises 19
Engineering Lore: Quality, Value, and Effort 20
4 Data Types 23
Bits, Bytes and Memory 23
Primitive Data Types 24
Integer Types 24
Floating-Point Types 24
Boolean Type 25
Character Type 25
Recap 26
Engineering Lore: Essential and Accidental Knowledge 26
5 Codes 31
Prelude: Number Systems 31
The Decimal Number System 31
The Binary Number System 32
The Hexadecimal Number System 34
The Octal Number System 35
Integer Codes 36
Unsigned Integers 36
Signed Integers 37
Another Prelude: Binary Fractions 39
Floating-Point Codes 40
32-bit IEEE754 Single Precision Floating Point Numbers 40
64-bit IEEE754 Double Precision Floating Point Numbers 42
Important Things to Remember About Floating Point Numbers 43
programming with java 7
Character Codes 43
ASCII 43
8-bit Codes 46
Unicode 47
Recap 49
Exercises 50
Engineering Lore: Problem Solving 51
Write, Draw, Visualize 51
Take Parameters to Extremes 51
Consider Small Cases 51
Create Your Own Failing Cases 51
If You Can Not Fix, Try Breaking 52
Explain the Probem to a Rubber Duck 52
Turn the Chess Board Around 52
Once it is Down, Attack all its Friends, too! 52
Example Problem: The King’s Rings 53
Example Problem: Cutting Pizza 57
Psychology of Problem Solving 60
Casting 71
Exercises 72
8 Looping 85
The for Loop 85
The while Loop 86
The do while Loop 88
The break and continue Statements 89
The break Statement 89
The continue Statement 90
Exercises 90
9 Logical Operators 93
The Logical Complement Operator ! (NOT) 93
The AND Operators, & and && 93
The OR Operators, | and || 94
The XOR Operator, ˆ 95
10 Strings 97
A Simplified Model of Computer Memory 97
Creating Strings 101
Methods of String 102
length 102
charAt 102
String Comparison 103
Exercises 105
programming with java 9
13 Arrays 115
Declaring and Creating Arrays 115
Accessing Individual Elements of the Array 116
Literal Array Initializers 116
Automatic Initialization 117
The length Member Variable 117
Enhanced for Loop 117
The Arrays class 118
Better Data Structures 119
Recap 119
Exercises 120
14 Classes 123
Defining the Class 123
Member Variables 123
Methods 124
Constructors 130
The this Reference Variable 131
Access Modifiers and Encapsulation 133
Immutable Classes 134
Recap 135
Exercises 136
15 Miscellanea 141
Packages 141
Javadoc 143
10 ya şar safkan
19 Projects 173
The Rules of Project Work 173
Project Level and Content 174
Project: Mastermind with Six Digits 174
Description of the Game Rules 174
The Goal of the Project 175
Required Work 175
Project: Scrabble Assistant 177
Description of the Project 177
Required Work 178
Preface
My efforts to write this book started in June 2022, with the intention
of using this as the textbook for the course I will be teaching in the
fall semester, CS101 - "Introduction to Programming".
These are interesting times - there is much interest in the area
of programming; significantly more so than the last two decades.
Young people, both students and new graduates, are as impatient
as young people have always been. They wish to forge wonders
and embark on exciting careers as soon as possible. There is also
an unprecedented amount of apparent learning methods. Online
courses, live courses, videos, tutorials, and textbooks. Most of them
are of the lowest quality possible; owing to the great demand -
anything sells.
Counting from the date of my Ph.D., my career is roughly
twenty years now. No simple description fits my career. I have
been teaching for twenty years, with very few breaks. I have been
a programmer, a software architect, a manager, a founder... I have
had many seats often with multiple hats.
I feel this puts me in a unique position to teach freshmen their
very first programming course. This is the course most of them
meet programming for the first time, and decide whether they like
it, and whether it is a viable career option for them.
I intend to design a course that will teach them the fundamentals
and provide them a solid foundation while at the same time giving
them sufficient practical information to feed their curiosity and
appease their impatience.
This textbook is one of the pillars of this course design. As such,
it is not intended to be a complete Java reference. Although modern
language features will be covered, the main focus is on the learning
experience.
To the Student
on familiar foundations.
Unless you have had deep personal interest and access to high
quality resources, your familiarity with programming is unlikely to
be level with your familiarity with the rest of the subjects. Program-
ming is different from the sciences; the sciences contain analysis,
understanding, and problem solving. Programming is largely a
design and synthesis activity.
The advice is clear: Pay special attention to the topic of program-
ming unless you have previous strong exposure. I am pretty sure
that as a student you are used to every high school teacher believ-
ing their course is the most important one and trying to convince
you, too. However, I am in the uncommon position that I could be
teaching your introductory physics course just as easily. Skipping
one lecture of programming is likely to hurt you much worse than
skipping one lecture of physics, especially in the first four weeks of
the term.
This course also has the distinction of being your first engineering
course. Whenever I have a class of engineers, I tend to spend some
time talking about what engineering is, and sharing some engi-
neering knowledge and lore with the students. It dawned on me to
incorporate that knowledge and lore into this book because why The toughest chains to break are those
not? So, each chapter contains a section called "Enginnering Lore", in your mind.. I had to break the
chains about what can and cannot go
which should be informative and fun to read. into a textbook.
This book represents my best effort to solidify my teachings to
students and present them to the student in a fun and digestible May the source be with you.
way. May it be useful to you.
1 Introduction
What is Java?
Popularity
The TIOBE web page describes the index as follows: The TIOBE index is about being able
to find resources on the web about a
The TIOBE Programming Community index is an indicator of the given programming language. What
they do in essence is comparing search
popularity of programming languages. The index is updated once
result counts for "Java Programming"
a month. The ratings are based on the number of skilled engineers and "Python Programming" across
world-wide, courses and third party vendors. Popular search engines multiple search facilities on the web.
such as Google, Bing, Yahoo!, Wikipedia, Amazon, YouTube and
Baidu are used to calculate the ratings. It is important to note that
the TIOBE index is not about the best programming language or the
language in which most lines of code have been written.
You can see the TIOBE index in Figure 1.2. Here, the results are
introduction 5
more clear. Python has finally overtaken C to reach first place. Java
is up there in third place.
You can find other measures of popularity. You will find that
Java is pretty much alive and kicking.
Recap
Exercises
What is an engineer? I like to look up the etymology of a word Well, "etymology" itself also needs a
when trying to answer such questions. Looking up "engineer" in definition - the word etymology stems
from the Greek word etumos which
the Online Etymology Dictionary yields the following: means true. As such, etymology is the
study of true meanings of words.
engineer (n.) mid-14c., enginour, "constructor of military engines,"
from Old French engigneor "engineer, architect, maker of war-
engines; schemer" (12c.), from Late Latin ingeniare (see engine);
general sense of "inventor, designer" is recorded from early 15c.; civil
sense, in reference to public works, is recorded from c. 1600 but not
the common meaning of the word until 19c (hence lingering distinc-
tion as civil engineer). Meaning "locomotive driver" is first attested
1832, American English. A "maker of engines" in ancient Greece was
a mekhanopoios.
So, the roots of most engineering lie in the military and war.
Why our structure-building, bridge-designing colleagues are called Figure 1.3: Trebuchets. Castle of
"Civil Engineers" rather than "Construction Engineers" or "Structure Castelnaud, France. These are consid-
ered to be siege engines, and the people
Engineers" is pretty much because of this. building them would have been called
If we attempt to define modern engineering, we can say skill, engineers.
craft, and abilty are still part of the job. We still build things, how- The joke is, Civil Engineers build
targets.
ever the definition of what we build has extended beyond mechan-
ical devices and structures to electrial, electronic, chemical, and
computational gadgets, devices, and contraptions.
In addition to wit, cleverness, and skill, the modern engineer has
to learn and make extensive use of the sciences and mathematics.
The main difference between a scientist and an engineer is that
the engineer intends to use available science to build her devices
- although it sometimes happens, it is not her intention to further
human knowledge by expanding the boundaries of science.
In the modern definition, we reject the meaning of the word
in the sense of deceitfulness and trickery. In fact, part of modern
engineering is the attempt to remove uncertainty and suprise, to
create order out of chaos instead.
So, here is my crystallized one-sentence definition of what an
engineer is:
Despite the name of the chapter, first we need to learn a few things
about programming concepts.
Programming Concepts
Source Code
Programming is a human activity. What a programmer writes in a
programming language is called source code. Source code usually
resides on files on a computer, and is human readable. Well, at least it is supposed to be human
Here is an example of Java source code. This content would readable.
normally go into a file called LatticePoint.java: All you are expected to understand
from the source code is that you can
package tr.edu.ozyegin.exam;
read the words in there! If you have
import java.util.Objects;
no idea what is going on, you are just
fine.
public class LatticePoint {
private int x;
private int y;
private int z;
@Override
public boolean equals(Object obj) {
if (obj instanceof LatticePoint) {
LatticePoint other = (LatticePoint)obj;
@Override
public int hashCode() {
return Objects.hash(x, y, z);
}
}
Machine Code
Machine code, also called "machine language" is the code that the
CPU cores in your computer can read and execute. This is the CPU stands for Central Processing
only thing that the CPU can "run". However, it is very difficult for Unit.
Interpreter
Some languages are interpreted. This means that, there is a special Of course, things are much more
program called an interpreter that converts your source code line-by- complicated in reality. For instance,
JavaScript is said to be interpreted,
line to into machine code, and runs it. however it does get compiled too.
Many languages employ a mix of
things. This "technology" thing is
Compiler bound to give you a headache.
Virtual Machine
A virtual machine is yet another special kind of program which
emulates a CPU. However, it emulates a CPU which does not really
exist.
The kind of code the virtual machine understands and can exe-
cute is known as bytecode.
The virtual machine employed by Java is aptly called the Java
Virtual Machine (JVM).
In essence, you can think of the JVM as an interpreter for Java
bytecode.
How do you produce the bytecode? You compile Java source
code into bytecode using the Java compiler (normally a program
named javac).
Why this complication? The idea is to make Java bytecode uni-
versal (you compile it only once) and be able to run it on any plat-
form for which you have a virtual machine for.
There are different versions of the Java Virtual Machine for dif-
ferent platforms; there is a JVM for Windows, and there is a JVM
for MacOS.
starting with java 11
Library
You need some sort of text editor to write your source code. Then,
you need to employ the Java compiler to compile it into bytecode.
Then, you need to employ the Java Virtual Machine (this is the java
command) to execute it.
There are programs (of course) that perform all these functions
together in a seamless way. These are called Integrated Development
Environments, or IDEs for short.
There are many IDEs available for Java, as a quick web search for
"Java IDE" will reveal.
Three of the long-time contenders are:
12 programming with java
Recap
Exercises
Exercise 2 Find out what other virtual machines exist apart from
the Java Virtual Machine, JVM.
Nothing new ever works. The credit for this law goes to Gerald
M. Weinberg, in his book "The Secrets
There are always new technologies on the market. New libraries. of Consulting". In its expanded form,
the law is Nothing new ever works,
New programming languages. New communication protocols. but there is always hope that this
New platforms. time will be different. and he names
the law "Pandora’s Pox".
This, of course, is not a bad thing. In fact, it is a good thing - this
is how progress happens. The problem is with the human disease
(Pandora’s Pox - see the margin) of hoping to circumvent the law
that nothing new ever works. An engineer should be immune to
this disease. There are two ways: Get the disease, suffer its effects,
and then build an immunity. Or, get vaccinated here and now: New
technologies are fine, but always use technologies that have gone
through the process of incremental improvement in your designs.
Let us close by saying that Java has gone through quite a bit of
incremental improvement. So, it makes better engineering sense to
use a language that has had over 25 years of incremental improve-
ment by a large community of contributors to a language that was
invented two years ago but looks very cool and shiny.
3 Hello, World!
makes you put everything into a class even when you have no
intention of working with objects.
So, this first line declares a class. "HelloWorld" is the name of the
class, for lack of a better choice - it hopefully conveys our intention.
The word "class" is a keyword in Java. Keywords are special
words defined by a language that can not be used for other pur-
poses (naming things).
The word before that, "public" is another keyword. It signifies The keyword public is one of the
that whatever follows, can be accessed from anywhere else in the access modifiers in Java. More on this
later.
program. It can be accessed by the "general public", so to speak.
The opening brace is also significant. It marks the beginning of These things {} are called braces, curly
the "body" of the class we just defined. Braces are used to mark the brackets, or even curly braces. For
brevity, I prefer braces, and I will use it
start and end of many things, and classes are just one of them. consistently.
public static void main(String[] args) {
Java is also picky about filenames. Since we have named our class When you use an IDE, as you are
HelloWorld, our program must go in a file called HelloWorld.java. expected to do matching class names
with file names comes (almost) natu-
If the filename and the name of the class inside do not match, the rally. However, you may get surprised
Java compiler will generate an error. when you change the class name
manually and start getting an error.
Running the program without an IDE is possible, however is
not instructive at this point. Getting your IDE of choice to run the
program is IDE specific, so it will not be covered here.
class
HelloWorld {
public static
void main(String[]
args) {
System
.out
18 programming with java
.println("Hello, world!"); }}
Comments
Comments are things you write into your source code that is only
intended for other human beings to read. The computer will ignore
them. Java, similar to most C-descendant programming languages There are also specifically formatted
has two (main) forms of comments. "Javadoc" comments, which can be
extracted by tools to create documenta-
The first form of comment is known as the "block comment" or tion. But we will not bother ourselves
"multi-line comment". The comment starts with a "/*" and ends with that.
with a "*/". These need not be on the same line. A block comment
can contain anything, except the combination of characters "*/"
which would mark the end of the comment. The block comment is the original
The second form of comment is called a "single line comment". form of commenting in the C lan-
guage.
The comment starts with a "//" and continues to the end of the
line. This kind of comment can contain anything, except the end-of-
line character.
The following modified "Hello, world!" program demonstrates
both types of comments:
/* The customary "Hello, world!" program in Java.
Unfortunately, this is not as simple as we would like.*/
public class HelloWorld {
public static void main(String[] args) {
// Do the actual printing here:
System.out.println("Hello, world!");
}
}
You can also find, or meet later, professors that still defend this
idea. These people are all seriously misguided. The correct under-
standing of the proper use of comments is as follows:
A comment is an apology to the person reading your code. By
commenting your code, you are saying "I am sorry, I could not
write the code simply and clearly enough, so now I have to explain
it to you in human language."
You should first spend enough time on your code to make it as
simple and as easy to understand as you can. To do this, you need Note that the rules for Javadoc com-
to learn about proper ways for naming things (classes, methods, ments are a bit different.
variables . . . ) and writing "clean code". And only then, if you can
hello, world! 19
Recap
• Java does not care about the exact use of whitespace, except
proper separation of tokens.
Exercises
Exercise 2
20 programming with java
Quality is value for someone. The credit for this definition also goes
to Gerald M. Weinberg, in his book
"How Software is Built".
So, quality is value assigned to something by someone. As such,
quality is subjective. As already stated, this understanding is central
to all work - you need to create and deliver value - to someone. So,
what is valuable is defined by who your customer is. This is exactly
where the saying "The customer is always right" comes from.
Of course, your customer is not always easy to identify. And
your customers may not agree on what is valuable. You may have
to choose whom to keep happy.
In a university course, your customer is the professor. This is ex-
actly because the professor decides what is valuable for the course.
The quality of your work is graded according to the value judge-
ments of the professor. You may think that at least in engineering Oh dear, are you in trouble or what?
a question has a definite answer but is usually does not. Even if it
did, the value judgement of the professor asserts itself in the choice
of what is asked.
In a rational world, the customer should only care about the end
result they receive. However, the world is not really rational. The
case where the customer ascribes value to the effort has been named
"The Locksmith’s Paradox" by Dan Ariely. Dan Ariely is a professor of psychol-
The story, as told to Dan Ariely by a locksmith is as follows: ogy and behavioral economics at Duke
University. His most groundbreak-
When the locksmith was just an apprentice, he usually took a long ing (in my opinion) book is titled
time to open locks. Occasionally, he would break the lock, and had "Predictably Irrational".
to replace it. The customers would pay for his labor, the replace-
ment lock, and give him a tip, and even thanked him. After so
many years, he became a master locksmith, now opening locks in
under a minute and without any damage. While the end result the
customer is getting is better and quicker, they do not tip him, and
they complain about the high fees he charges rather than thanking
him.
I had a similar experience back in 1998, when I was working at
the Los Alamos National Laboratory in New Mexico as a graduate
student. I managed to lock the key in my car with the engine still
running. I called a locksmith. He said right on the phone that his
fee will be $40 if he shows up. I agreed (well, I felt so stupid, I
hello, world! 21
would have agreed to more.) He showed up, and it took him about
eight seconds to open the door. I paid him his $40, and he left. He forced the top of the car door with
I could see the reason he told about the fee up front. People feel a plastic covered crowbar, reached in
with a long metal arm, and unlocked
ripped off because it was so quick. Personally, I did not feel ripped it from the latch on the handle. He did
off at all. If anything, I admired the guy for his knowledge and skill, not even touch the keyhole. In case
you were wondering.
and was very satisfied that the problem got solved so quickly.
Ascribing value to effort and/or labor is yet another human
disease. It tends to penalize high skill and efficient work, instead
idolizing wasted effort. As you can tell by the anecdote above, I was
unaffected by this disease so many years ago, and I am quite im-
mune to it today. I ascribe no value to effort that does not produce
valuable results.
Seemingly paradoxically, I value and respect human effort and
labor greatly. True respect for human effort is shown by preventing
its waste, and making sure it is used effectively and efficiently.
Pronouncing some useless, worthless result valuable just because a
lot of effort was expended on it is the worst kind of disrespect for So, arguments like "I worked really
human effort and labor. It encourages further waste. When faced hard on that homework, so I should
get a better grade" will utterly fail. You
with wasted effort, the best you can do is explain why the end can not ask for a better grade, but you
result is worthless, and give honest yet respectful feedback. can ask for feedback on how not to
waste your efforts next time.
Ultimately, the work of an engineer to build things valuable for
a customer effectively and efficently. Effective means that it does
what it is supposed to do, and efficient means that it uses the least
amount of the triple trade-off tiangle: Money, time, people.
4 Data Types
is the thing that can be either a zero or a one. The name "bit" is a
contraction - it stands for binary digit.
As a mental image, you can think that a byte looks something
like Figure 4.2.
24 programming with java
Each of the cells is a bit, and the number inside it is its value.
The whole rectangle is a byte. Note that any bit pattern (or this
particular bit pattern) does not automatically mean anything at all. A code is a table which lists corre-
We assign meaning to bit patterns according to our wishes - what spondence between bit patterns and
symbols. There is no way to know
we want to represent using them. what a particular bit pattern means
Back to the question of how many bits of RAM my computer without knowing what the code is.
contains: Believe it or not, my computer contains: If we answered this question back
in 1984 when I got my Commodore
64, the answer was 524 288 bits. The
549 755 813 888 bits of RAM amount of RAM in "my computer" has
increased by a factor of 1 048 576 in 38
That number is calculated as follows: Due to historical reasons, years. That is roughly a 44% annual
when talking about RAM capacity, a gigabyte is not 1 000 000 000 increase!
bytes, but rather 230 = 1 073 741 824 bytes. Multiply that by 64 to get
the total number of bytes, and then multiply the result by eight to
find the number of bits.
Integer Types
These are used to represent integers, positive and negative. The
only difference of the four types is their sizes, and correspondingly,
limits of the values they can take. Figure 4.3 summarizes this infor-
mation.
Type Minimum Value Maximum Value Size in Bytes Figure 4.3: Integer types in Java, their
minimum and maximum values, and
byte −128 127 1 sizes in bytes. The "default" type to
short −32 768 32 767 2 use, unless you have reason to do
otherwise is int.
int −2 147 483 648 2 147 483 647 4
long −9 223 372 036 854 775 808 9 223 372 036 854 775 807 8
Floating-Point Types
The name is a bit intimidating - saying "integers" was fine. Ev-
eryone has heard of integers. What is a floating-point number? A
floating-point number is an approximate, limited precision way a
computer can use to represent real numbers. A few mathematicians probably want
to strangle me now. I do not care!
data types 25
1.60217663 × 10−19
In this form, the part to the left (1.60217663) is called the signif-
icand, and the number in the exponent (−19) is called the exponent
(duh!). The significand holds the significant digits of the number, You can also think of the exponent
while the exponent represents the magnitude (size) of the num- as telling where the decimal point is.
It can make the decimal point "float
ber. A floating-point number packs these two things together to around" when its value changes. This
represent numbers. is the origin of the name "floating
point".
The two different floating-point types have different number of
Of course, everything is in base two
significant digits and range for the exponents. These are shown in rather than base ten. But the essence is
Figure 4.4. Both types conform to the "IEEE Standard for Floating- exactly the same.
Point Arithmetic", also known as IEEE 754.
Type Smallest Value Largest Value Size in Bytes Figure 4.4: Floating-point types in Java.
float ±1.4 × 10−45 ±3.4 × 1038 4
double ±4.9 × 10−324 ±1.7 × 10308 8
With a float, you get a bit over 7 significant decimal digits (this
includes the digit to the left of the decimal point). A double will What really happens is, float reserves
give you almost 16 significant decimal digits. Although the name 23 bits for the significand. However,
since for any binary number, the
double is meant to mean double precision, it actually gives you more leftmost bit is always 1 (think about
than double precision. it - with the exception of zero) it is
not stored but implied. This gives
Note that a float has the same size as an int (both 4 bytes or 24 bits precision. In decimal, that
32 bits) and a double has the same size as a long (both 8 bytes or corresponds to 24 · log10 2 = 7.225. A
double reserves 52 bits giving 53 bits
64 bits). This means the same bit patterns mean different things
of precision with the implied bit. That
- their coding is different. As such, the computer will do different results in 53 · log10 2 = 15.955 decimal
things when you try to add two ints and two floats. The data type digits of precision.
defines the coding, and the rules of operating on the bit patterns to
get the expected results. This is the heart and soul of data types.
Boolean Type
Yet another strange name. This time, it is the name of a person,
George Boole (1815-1864) an English mathematician, philospher,
and logician. His first book, "The Mathematical Analysis of Logic"
introduced what is now known as Boolean algebra. Boolean algebra
is the algebra of truth values - true and false.
The Boolean type is a type which can take on only two values -
true and false. It should be obvious that such a thing requires just
one bit to store. The boolean type is the simplest type there is, but
it is also the only primitive type the Java standard does not define a
size for.
Character Type
Remember the String "Hello, world!"? Each letter, comma, and
exclamation mark in there is a character. The primitve type char
can hold one character. The size of a char is two bytes. Once again,
26 programming with java
Recap
• It is true that computers use only zeroes and ones to store infor-
mation. But computers have a lot of them.
• There is a boolean type, which can take the values true or false.
Its size is unspecified.
• There is a char type, which can hold a single character. Its size
is two bytes. The heart and soul of data types is that each data
type assigns a different meaning to the same bit pattern. The bit
patterns do not mean much by themselves, but we are free to
assign them any meaning we need.
Aristotle is a Greek philosopher who lived between 384 and 322 BC.
He made the distinction between essential and accidental properties Note that accidental here is not used in
of an object. By essential he means those properties that the object it common meaning of "an unwanted
event, possibly causing harm". You
in question must have - they are part of its identity, or essence, so to can think of it as "something that just
speak. On the other hand, accidental properties are properties that it happened to exist".
just happens to have - it may have these properties independently
data types 27
In undergraduate education, the goal should be to transfer as It is not about the exams. It is about
much essential knowledge as possible. If you graduate equipped what you learn.
d n d n −1 d n −2 . . . d 2 d 1 d 0 = ∑d k · 10k
need every digit to be able to take
values up to 9, one less than the base.
k =0 Otherwise, things will not work.
dk ∈ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
All this comes very naturally, and in our minds their decimal
representation is the identity of those numbers. The point here is
to remember and realize that the decimal system is in fact just one
possible representation method for numbers. Then, we can think
about other number systems.
32 programming with java
1101001010110
Value 4096 2048 1024 512 256 128 64 32 16 8 4 2 1 Figure 5.3: The interpretation of a
212 211 210 29 28 27 26 25 24 23 22 21 20
Digits 1 1 0 1 0 0 1 0 1 0 1 1 0
binary number. Again, the value of
each digit is dependent on its position.
The values are given in decimals.
You can verify that the bit pattern really corresponds to 6742 by
adding the numbers in the boxes corresponding to ones. There I recall being taught how to do
are methods for conversion between binary and decimal, but the decimal-binary conversions in fifth
grade. We were also taught base five
correspondence is not obvious. Except very small numbers, using which turned out to be useless.
binary is impractical for humans.
The notation to denote binary numbers as used in Java is to
prepend the number with 0b. So, 0b1101001010110 is the way do
properly denote a binary number in Java, and we will use this in
this book to avoid confusion when necessary.
It turns out these are numbers, they do contain letters, and for
good reason. Hexadecimal means base sixteen. With base sixteen,
you need digits up to fifteen - but our everyday decimals end at
nine. What to do? Instead of inventing new symbols and giving a
headache to everyone, we use existing familiar letters for the rest of
the numbers.
In hexadecimal, A stands for 10, B stands for 11, C stands for 12,
D stands for 13, E stands for 14, and F stands for 15. And of course,
our positional values are now powers of sixteen rather than ten.
You can see the representation of good old 6742 in hexadecimal
in Figure 5.8.
starting from the right to get 0001 − 1010 − 0101 − 0110 (with a lit-
tle padding on the left with zeroes to complete the group of four). Eight bits are a byte. A nybble is a
Now, convert each group into hexadecimal: 1 − A − 5 − 6, which is group of four bits.
just 0x1A56.
When working with an underlying binary systems, hexadecimal
is practical enough for humans to use. The notation is suitably
shorter, while simultaneously enabling easy conversion to binary.
codes 35
What is the nasty error? The common notation for octal numbers
is to prepend the number with an (unnecessary in decimal) zero.
So, when you type 010, you may think it is a decimal 10. However,
the leading zero denotes this as an octal number, and that is in fact
a decimal 8. Argh.
36 programming with java
Integer Codes
Unsigned Integers
You probably have an educated guess about "unsigned" means.
It means that the code does not worry about a sign - there is no
place in the code itself to store the sign. So, only zero and positive
numbers can be expressed with an unsigned integer code.
The most common code used for unsigned integers is binary code.
This is using a fixed number of bits to represent a number. For all
integer codes, we will be considering 8-bit versions which is easy
to follow. Making the numbers of more bits does not change the
behavior, only makes the numbers longer.
The representation of zero is pretty straightforward, as in Figure
5.11.
The largest number you can represent with eight bits is 255, as in
Figure 5.12.
Signed Integers
More often than not, you want to be able to use negative values as
well as positive values in your integer types. The obvious idea is to
use half of the available range for positive values, and the other half
for negative values.
The most common way of doing this is called "2’s complement
signed integers".
First let us define and understand the operation "1’s comple-
ment" performed on a finite-size binary number. The 1’s comple-
ment of a binary number is found by changing every 0 bit to a 1
and every 1 bit to a 0. The operation is really simple, and it is its
own inverse operation, as you can see in Figure 5.16.
Note that adding a number and its 1’s complement together will
result in a number composed of all ones.
38 programming with java
• All numbers with the leftmost bit zero are positive (or zero).
• All positive numbers have the same values as the unsigned case.
Floating-Point Codes
( 16777217 ) 10 = ( 1000000000000000000000001 ) 2
The number we started with is 2 24 + 1, which makes it a 25-bit
number. If we normalize the number, it becomes:
1.000000000000000000000001 × 2 24
What am I going to store in the number? The sign bit is zero,
because this is positive. The exponent I will store is 127 + 24 =
151 = ( 10010111 ) 2 . That also works.
The significand I am going to store is what is to the right of the
binary point. And I can only store 23 bits. There are obviously 24
42 programming with java
bits in there. So, the rightmost bit will be dropped, and I will store
00000000000000000000000 as the significand!
What just happened? I lost the 1 at the end. I tried to store
16777217, but since I dropped the 1 at the end, I ended up storing
exactly the same stuff as 16777216. In fact, if I read this number
back, I will read 16777216. This is what is called loss of precision.
The larger the integer you try to store, the more of it will be cut off
from the end.
It turns out that the above example is not sufficient for a good
understanding of how loss of precision happens. As such, here is I have been told this by two students
an example that loses way more precision. in Fall 2023. I find they are right,
instead of pointing to the boundary, it
The world population clock, on November 4th, 2023 at 21:26 is a better idea to point at an extreme
UTC+03 gives the following figure for population of the world: case.
• Some exact decimal fractions like 0.2 and 0.3 are not exact in
floating point.
Character Codes
ASCII
ASCII stands for "American Standard Code for Information In-
terchange" and is pronounced as "ask-key". ASCII was originally
developed in the 1960s, and was updated well into the 1980s.
ASCII is a character encoding system, which is essentially a way
to match characters with numeric codes, or bit patterns. In general,
when encoding characters, a number (or bit pattern) corresponding
to a character is called a code point.
ASCII was designed as a 7-bit code. The (inexact yet simplified)
explanation is that they needed codes to reprsent upper and lower
case letters of the English alphabet (a total of 2 × 26 = 52 codes)
decimal digits (10 codes) space and punctuation, which easily goes
over 64 code points. So, 6 bits was not sufficient. An 8-bit code was
44 programming with java
You can see the actual ASCII code table in Figure 5.24. The first
two sticks (group of 16 characters, a term hardly ever used these
days) contain control characters. The main reason is that at the
time, computer output or digital communication was carried out
with what we call teleprinters, teletypes, or TTY for short. These
devices were essentially printers that would print incoming digital
information on paper - remotely controlled printers, so to speak.
As such, the whole protocol of remotely communicating with
these devices had to be present in the character set itself (well, other
designs were possible, but this made perfect sense at the time). A
full explanation of every control code is unnecessary and futile, we
will go through a few that are still relevant today, and a couple that
are fun to know.
Character code 7 is BEL in the table, which stands for "bell".
What this normally did is literally ring the bell (which TTY devices
had) to alert the operator. This still works as of today; if you try
to print the character with code 7, it will make the computer play Unfortunately, the IntelliJ IDEA
some sort of beep sound. environment will not honor this code
and will play no sound. However, if
Just to satisfy your curiosity, the following statement will attempt you run it directly it still does work,
to output the character code 7: which I confirmed on my Macbook
Pro.
System.out.println("\u0007");
The meaning of the DEL character (as you might have already
guessed it) is "delete". In the good old days, programs lines were
fed into the computers with what is known as a "punched card".
You can see what a punched card looks like in Figure 5.25. Each
column corresponds to a character code, and the whole card cor-
responds to a line of text. A computer program would consist of
a deck of these cards. Of course, there were special typewriter-like
46 programming with java
devices, which you would use to punch the proper holes on these
cards.
Now, what happens if you make a typing mistake? How do you
delete the character? Closing the holes back up is really impractical.
Throwing away a whole card for one mistake is a waste. A good
solution is, if and when you make a mistake, go back one place and
punch through all holes so that the whole column consists of holes.
In turn, when the computer (which senses the holes physically or
optically) ignores any such column, just moving to read the next
character. This automatically makes "all holes" which is "all ones" a
delete character. Therefore, the code for DEL is 0b1111111 which is
127.
8-bit Codes
What followed ASCII was a multitude of 8-bit codes. Increasing the
number of bits from 7 bits to 8 bits increases the number of avail-
able character codes from 128 to 256. There were a multitude of
8-bit character sets; these codes essentially extended ASCII, meaning
that the lower 128 codes were common to all of them.
Over time, more 8-bit character sets were created to support vari-
ous languages of the world. Before the Internet became widespread,
most computer usage was limited to a single system, or mostly a
single type of system, so using a character set that fit your language
covered most, if not all of your needs.
When the proliferation of the Internet brought systems together,
and people started to share documents written in all sorts of char-
acter sets, the need for a better solution was felt more and more.
In theory, you could and should serve every document while also
specifying its character set, and the person viewing your document
should have no trouble at all. However, in practice any documents
not in the web’s default character set (Latin-1 or ISO-8859-1) had a
very good chance of displaying incorrectly on someone’s screen.
Unicode
The idea of Unicode can be traced back to 1987. In 1988, Joe Becker
published a draft proposal for Unicode, in which he described a
16-bit encoding:
Unicode is intended to address the need for a workable, reliable
world text encoding. Unicode could be roughly described as "wide-
body ASCII" that has been stretched to 16 bits to encompass the
characters of all the world’s living languages. In a properly engi-
neered design, 16 bits per character are more than sufficient for this
purpose.
You can read about the exact evolution of the Unicode from
other sources, so trying to replicate that here is of little practical
use. However, let us just state that a 16-bit encoding turned out to
be insufficient, and Unicode ended up separating the definition of
the character set from the encoding used in practice. The follwing is
extracted from the Unicode Standard, version 15.0:
The range of integers used to code the abstract characters is called
the codespace. A particular integer in this set is called a code point.
When an abstract character is mapped or assigned to a particular
code point in the codespace, it is then referred to as an encoded
character.
48 programming with java
So, the Unicode Standard defines a code space, and code points
which correspond to abstract characters. It does not specify how The Unicode Standard defines abstract
these code points will be represented on the computer; that is left to characters as opposed to glyphs, which
are the specific way a character is
the specific encoding. graphically represented; a collection of
The three Unicode encodings of interest are: glyphs is a font, which is a term you
are much more likely to be familiar
• UTF-8 with.
Here, UTF stands for Unicode Trans-
• UTF-16 formation Format.
• UTF-32
UTF-8 represents each code point using one to four bytes. Specifi-
cally, it uses a single byte to represent ASCII characters, making it
fully backwards compatible with existing ASCII text.
As such, UTF-8 has become the de facto standard for the web
and most documents because of its compactness and backward
compatibility.
UTF-16 represents each code point using one or two 16-bit units.
This is the encoding used internally by Java. While a char in Java
is always 16 bits, some Unicode characters will be encoded as two
chars. Those characters are called supplementary characters, and
have code points larger than U+FFFF. And we used the correct notation to
refer to a Unicode code point.
UTF-32 represent each code point with a single 32-bit unit. This
means that this is a fixed size encoding as opposed to the variabil-
ity in UTF-8 and UTF-16. While this has the advantage that the
values of each Unicode code point is stored directly, the disadvan-
tage is that it expands everything to 32 bits in memory even though
the maximum number of bits required by the Unicode standard is
21bits.
codes 49
Recap
• The number system we use every day is called the decimal num-
ber system. Its base is ten.
• There are also octal numbers, base eight. Octal numbers are
shown with a prepended zero, so 010 is actually 8.
• UTF-16 is what Java uses internally. It uses either one or two 16-
bit units to encode all Unicode code points. Non-supplementary
characters with code points less than U+FFFF fit into one char in
Java.
Exercises
Problem solving is an important skill, especially for engineers. Af- I did not have a course on problem
ter all, problem solving is part of the job definition for an engineer. solving, either. The fact that most
problem solving in undergraduate
Despite this fact, there is rarely, if at all, any coursework geared education is of the type "here is the
toward teaching the well-known practices of problem solving. In- problem, here is the formula, now go
ahead and apply it" does not help.
stead, students are expected to learn problem solving by "diffu- Real life problems rarely come with
sion", that is, by seeing how problem solving is done in different their solution methods attached.
disciplines.
There are two problems with this: First, problem solving work is
given to teaching assistants, who have little experience themselves
in problem solving. Second, efficient learning happens when the- There will be examples. I will practice
ory and practice complement each other - otherwise this learning what I preach.
If you have a solution that works for some cases, but fails for oth-
ers, try to fabricate your own failure cases, and make them minimal
while you are at it.
52 programming with java
think this is as much as anyone can kick this problem. Or so I thought. By the time I finished
writing up the solution, I discovered
there was more to kick.
Example Problem: The King’s Rings
The king had 1000 grams of gold, and wanted to have 100
pure gold rings of 10 grams each be made for himself. For this, he
appointed a jeweler, and handed him the gold.
The jeweler took his time, and was finally summoned to present
the rings. He brought 10 pouches with him, each containing 10
rings.
You, as the chancellor, have received an intelligence report that
the jeweler has been unable to contain himself, and stole some of
the gold. The intelligence report also says that to minimize his
chances of being caught, he stole 1 gram of gold from 10 rings only,
and put all those rings in the same pouch. So, nine of the pouches
contain 10 rings of 10 grams, while one pouch contains 10 rings of 9
grams each.
Dutifully, you inform the king about this report. The king is
naturally furious, but wants to be fair as well. He orders the Royal
Weight Scale to be brought. Surprisingly, this weight scale is an
electronic one, and displays on its screen the weight placed on it
very accurately and precisely.
Then, the king turns to you, and says: "Here are the ten pouches,
and the rings. You can take as many rings as you wish from any of
the pouches and place them on the Royal Weight Scale. Then, you
press the button, and see the weight. Then, you must be able to tell
me exactly which pouch contains the rings which the jeweler stole
the gold from. But, -this is important- you can use the Royal Weight
Scale only once. If you fail, I will have you thrown in jail instead of
the jeweler, because you are either commiting slander, or are not
smart enough to be the chancellor."
case? Less rings per pouch looks like it could cause problems.
Two pouches with one ring each is still solvable - any case of
two pouches is. So, we need at least three pouches to fail. Three
pouches with one ring each. Then, whatever we do, we can not take
a different number of rings from each pouch. We can take 0 or 1
ring from each pouch which gives two cases, but there are three
pouches. So that fails.
If you think a little about it, in the general case, for n pouches,
you need at least n − 1 rings in each pouch. Otherwise, the problem
can not be solved as stated. This last observation is actually "Turn-
ing the Chess Board Around"; except that there is no way of fixing
the solution for the impossible cases.
f ( x1 , x2 , . . . x n ) = c1 · x1 + c2 · x2 + . . . c n · x n
I must confess that I have not gone to this degree of investiga- Then again, it turns out once you have
tion on this problem myself. However, this should give you an idea the solution to the first problem, this
is not so hard. It took me about a
about how to keep working on a problem once you are done with minute of thinking to come up with
it. the general solution.
This concludes our discussion of this problem.
One cut is easy. Two pieces, obviously. Two cuts is also easy,
resulting in four pieces. As an afterthought, I have also considered
zero cuts, which is a very valid number of cuts (negative numbers
do not work) which results in a single piece.
So, if you consider zero, one, or two cuts, you get one, two, four
pieces. If you stop here, things are a bit misleading. It looks like
every new cut doubles the number of pieces, result in powers of
58 programming with java
two. However, three cuts breaks the pattern. Whatever you do, the
best you can do is get seven pieces.
With four cuts, the drawing already gets difficult. But, it is still
possible to do within human limits, and it is worth it to get one
more data point. Some care in drawing shows that with four cuts
we get 11 pieces.
The first cut divides the pizza into two. With the second cut,
we can break things - we can avoid intersecting the first cut. If we
do that, we will get three pieces rather than four. This means the
following:
To get the maximum number of pieces, each cut must intersect
the other cuts.
Now, consider already having two cuts intersecting at a point,
which gives four pieces. With the third cut, we can do a cut which
intersects none of the previous cuts, which will cut out just one
additional piece, but we already know that method of breaking
stuff. There is a new way now, though. If we intersect with the
other two cuts at their existing point of intersection, we get six
pieces rather than seven. This failure mode means the following:
To get the maximum number of pieces, each pair of cuts must
intersect at a unique point.
codes 59
P(n) = 1 + 1 + 2 + . . . + n
This can be simplified:
n ( n + 1)
P(n) = 1 +
2
The answer to the original problem now seems to be but a trivi-
ality. We just need to compute P(8):
8(8 + 1)
P (8) = 1 + = 1 + 4 · 9 = 37
2
So, with 8 cuts you can create a maximum of 37 pizza pieces.
60 programming with java
If you think you will fail then you will definitely fail in solv-
ing the problem. Rather than thinking "I can not solve this", you
should be thinking "I have not solved this yet".
Declaring Variables
Now, what we are saying has change a bit into: Dear computer,
please reserve sufficient space in memory to store a 32-bit integer.
And, we are going to call that reserved space x. Oh, before I for-
get, put the value 5 into that memory space we just reserved. Ok,
thanks, bye.
The 5 you see there is called a literal. Any value you type directly
into the source code is called a literal. Literals also have types, and
62 programming with java
there are few formats you can use to type literal values into the
code; but now we will just push forward and leave the details for
later.
While I hate the practice to the point of not wanting to teach it, it
is possible to declare more than one variable of the same type in one There are more practices allowed by
line. For example: programming languages which no-
body should be doing, ever. However,
int x = 5, y, z = 3; people do these, and you are likely
to see them in code. So, I still have to
teach them, even just for making you
In this case, x, y, and z are all of type int. Note that y has no "know your enemy".
initial value. If you were to do:
int x, y = 7;
x = x + 2;
System.out.println(x);
}
}
If you run this program, you can verify that it prints out a 9 and
terminates.
Although it is a very short program, there are quite a few things
to understand in here. Let us go through this line-by-line.
int x = 7;
This line has two things going on. One is an assignment. This is
very similar to the case of the variable declaration with an initial-
izer. In fact, the variable declaration with an initializer is a short-
hand for doing two things: Declare the variable, and assign a value
to it. Here, we see an assignment operation on its own. The equals
sign = is the assignment operator. Assignment means "take the
value on the right, compute it if necessary, and put in into the vari-
able on the left".
The right hand side contains an operation. The operation is ad-
dition, which is signified by the addition operator, which is +. The
addition operator takes two operands, and adds their values to-
gether, creating a new value which is the sum of the two operands.
The computer does the following: To do the assignment, it needs
to calculate what is to the right of the equals sign. There, it sees the
variable x and the literal value 2. It accesses the variable, and gets
the value 7. Then, it is prepared to do the addition. It adds 7 and 2,
obtaining the value 9. Now, the assignment happens, and the value
of 9 gets written into the memory space reserved for the variable x.
System.out.println(x);
This last line, as you should know from the "Hello, world!" pro-
gram, prints the value of x on the screen, resulting in a 9.
Arithmetic Operators
• + Addition
• - Subtraction
• * Multiplication
• / Division
• % Modulus (remainder)
Division
Division requires special attention, specifically because the set of
integers is not closed under the division operation. This just means How mathematical of me.
when you divide two integers, you may get something that is not
an integer.
If you read and understood the rules of type promotion in the
previous section, then you should realize there is a problem: If you
divide two integer types, they will both be automatically promoted
to ints if necessary, and the result of the division will be an int!
What?
Well, there is such a thing as integer division. You must have done
this in second grade - you divide 14 by 3, the quotient is 4 and the
remainder is 2. This is what Java will give you when you perform
division on two integers.
So, computing 1/2 will result in a 0.
The results of integer division can be mystifying when negative
numbers enter the picture. The easiest way to understand how
it works is to think of doing the exact division in real numbers,
and drop the fractional part. This is equivalent to doing the exact
division in real numbers, and always round towards zero. So, 1/2,
−1/2, 1/ − 2, −1/ − 2 all result in 0.
Also, if you are performing integer division, and the divisor is
zero, your program will throw an exception. This means that you will
not get a result, and your program will stop printing an annoying
error message. Remember, division by zero is strictly forbidden in
integers.
If at least one of the operands is floating point, what you more-
or-less expect happens. Also, in the case of floating point operands,
variables, literals and mathematical operators 65
Modulus (Remainder)
In mathematics, the modulus operation is commonly defined for
integers. When you calculate a % b in Java where both operands
are integral types, you are in well-defined territory. The modulus
operator can actually be expressed as:
a % b = a − ( a/b) ∗ b
The division is (obviously) to be interpreted as integer division.
Recall that integer division always rounds towards zero.
When the right operand is positive, the sign of the the remain-
der is the same as the sign of the left operand. This means things
change around zero a little bit:
−3 % 3 = 0
−2 % 3 = −2
−1 % 3 = −1
0%3 = 0
1%3 = 1
2%3 = 2
3%3 = 0
4%3 = 1
When the right operand is negative, all results are the same as
the case where it was positive:
0% −3 = 0
1% −3 = 1
2% −3 = 2
3% −3 = 0
4% −3 = 1
Operator Shorthand
If there is one thing that has been done more than anything else in
a program in the history of programming, it is increasing the value
of a variable by one. So, there is a special shorthand for increasing
and decreasing the value of a variable by one. Admittedly, decre-
menting is done much less than incrementing, but it kind of tagged
along because of symmetry.
The increment operator is ++ and the decrement operator is
-, and these are unary operators - meaning they act on a single
variable.
The following line
x += 1;
y = 3 + x++;
System.out.println(x);
System.out.println(y);
y = 3 + ++x;
System.out.println(x);
System.out.println(y);
Now, while calculating y, the computer will use the new value of
x, after the increment happens. So, y will get the value of 3 + 2 =
5, while the value of x at the time of printing will still be 2.
In some computer courses, some professors tend to ask students
to resolve things like:
int x = 7;
int y = 8;
System.out.println(x);
System.out.println(y);
Can you guess what my answer to this is? I do not care. Do not
write code like that. Writing complicated code is easy. Analyzing "Debugging is twice as hard as writing
it is as futile as it is difficult. Trying to do too many things in one the code in the first place. Therefore,
if you write the code as cleverly as
line is really bad programming. How many is too many? Three is possible, you are, by definition, not
too many. Using more than one variable with an increment and smart enough to debug it." – Brian
Kernighan
68 programming with java
Literals
Literals are values you type directly into the program. These also
have their types, and are subject to conversion rules, quite similar to
but not exactly the same as variables.
Integer Literals
Trying to type an integer value larger than the limits of int even
if it is assigned to a long variable fails:
long j = 4000000000; // This fails, since number is too large for int.
Note that the letter L can be lower case (l) as well, but this can be
easily confused with the digit one (1) so using the upper case L is
strongly recommended.
variables, literals and mathematical operators 69
Floating-Point Literals
Floating-point literals are more complicated than integer literals.
They can certainly have an integer part, but they may also have a
fractional part separated with a decimal point. In addition, they can
also have an exponential part, which denotes the power of ten.
Let us just look at a few examples:
double x = 4.45;
The compiler will not attempt to put a double literal into a float
variable. Here is how to make that work:
float y = 4.45F; // This works. Appending F makes the literal a float.
You can also make use of an exponential part to express large (or
small) numbers as follows:
double z = 6.022E23;
One possible fix is to put a decimal point at the end of the num-
ber, which will make the literal interpreted as a double.
double x = 1_000_000_000_000_000_000_000.; // This works.
Since Java 7, the use of underscores (_) are allowed in any numeric
literals between any digits. This is very useful for making numbers
more readable for humans. So, taking a previous example:
long j = 4000000000L; // Hard to read exactly what this is.
Character Literals
Character literals are literals you can assign to char variables. They
are used to represent a single character. A character literal is simply
a character surrounded by single quotes:
char c = ’x’;
This assigns the character x into the char variable c. Note that
you are not allowed to put more than one character into a character
literal. The following will not compile:
char c = ’xy’; // This will not compile.
Boolean Literals
Boolean literals are perhaps the simplest of them all. There are only
two literals you can use in the code, which are true and false.
boolean x = true;
boolean y = false;
variables, literals and mathematical operators 71
Casting
System.out.println(b);
}
}
Using a cast will tell Java to "go ahead and do the conversion
anyway, if there is any loss, it is my problem". Here is the version
that will compile:
public class Main {
public static void main(String[] args) {
int x = 7;
byte b;
System.out.println(b);
}
}
following program:
public class Main {
public static void main(String[] args) {
int x = 255; // This will not fit into a byte.
byte b;
System.out.println(b);
}
}
If you run the program, you will see that it prints −1. You might
have expected it to print 127, which is the largest value a byte can
hold, but instead the bit pattern is forced into the variable, drop-
ping any excess bits. If you have understood the chapter on codes,
you should be able to figure out why this prints a −1.
When you do a conversion from a floating-point type to a integer
type, you always need a cast. Such a cast acts a bit "more intelli-
gently" than the integer casts.
Exercises
Exercise 2 Consider the following slightly modified version of the public class Main {
program in the chapter: public static void main(String[] args) {
short x = 9;
x = (short)(x + 2);
public class Main {
System.out.println(x);
public static void main(String[] args) { }
short x = 7; }
x = x + 2;
System.out.println(x);
} main reason of the compilement error was the given
} +2 is an integer, thats why it takes the x as an integer
the second time that we wrote it
262196 · 28813
101
Verify that this works out to be an integer, and is exactly:
74 798 548
System.out.println(262196*28813/101);
System.out.println(262196/101*28813);
System.out.println(28813/101*262196);
}
}
Do they all print the same value? Explain the three results.
Comparison Operators
Branching
The if Statement
The general form of the if statement is as follows:
if (<condition>) {
<true block> Figure 7.3: The if/else statement
} else { branching. A value of true goes left
<false block> (if), and a value of false goes right
} (else). They eventually merge, of
course.
When structured like this, you can be sure one and only one of
the blocks will be executed. As above, you can omit the final else
block, in which case at most one of the blocks will be executed. If
multiple conditions are true, the first one encountered from the top
is the one that "counts".
Here is a quick example:
public class Main {
public static void main(String[] args) {
int x = 2;
int y = 7;
if (x > y) {
System.out.println("x > y");
} else if (x < y) {
System.out.println("x < y");
} else {
System.out.println("x = y");
}
}
}
When you run this, when the computer reaches the if statement,
it evaluates x > y. Because 2 > 7 is false, it skips the first block.
Then the second condition, which is x < y is evaluated. Because 2
< 7 is true, that block is executed, printing "x < y" on the screen.
The final else block is skipped entirely.
We can modify the program a little to see some interesting be-
havior. Now consider the following slighly modified program:
public class Main {
public static void main(String[] args) {
int x = 3;
int y = 3;
if (x >= y) {
System.out.println("x >= y");
} else if (x <= y) {
System.out.println("x <= y");
} else {
System.out.println("x = y");
}
}
}
Now, the conditions in two if tests are not mutually exclusive. This
means that they can be true at the same time. Note that the values
of the variables are now the same, so both conditions are true. 3>=3
is true and 3<=3 is also true. If there is a voice in your head telling
Which block will execute? The execution starts from the top, you that 3=3 so 3>=3 is false, tell that
voice to shut up.
so the very top condition will be checked first. Since it is true,
that block will execute, and the other condition will not even get a
chance to get checked.
When using an if-else-if-else ladder like this, there are a few
things to consider about the order of the conditions (and the blocks
they control).
A switch statement has entry points and exit points. Entry points
are the case labels and the default label. The exit points are the
break statements, or the end of the switch statement.
The choice of entry point depends on the decision value, which
is computed at the beginning of the switch. A lot of the time it is
just the name of a variable, but it can also be something computed
like x+2. The only constraint is that it has to evaluate to an integer
value.
Once the decision value is known, the entry point is chosen. If
there is a matching case label, execution jumps there. If there are
no matching case labels, but there is a default label, execution
jumps there. If the decision value does not match any case label,
and there is no default label, the switch block is skipped entirely.
Once execution is inside the switch block, sequential execution
resumes until an exit point is reached. During this sequential exe-
cution, coming across an entry point (which is either a case label or
a default label) is a "no operation" - an entry is not an exit.
If you do have a default case, it is good style to have it as the
last thing. Also, while not necessary, it is also good style to put in
the last break.
The switch statement is used less often than it should probably
because it is somewhat confusing, and a bit dangerous. Let us look
at a couple of examples to see typical cases, and typical errors.
public class Main {
public static void main(String[] args) {
int day = 3;
more operators and branching 79
switch (day) {
case 1:
System.out.println("Sunday");
break;
case 2:
System.out.println("Monday");
break;
case 3:
System.out.println("Tuesday");
break;
case 4:
System.out.println("Wednesday");
break;
case 5:
System.out.println("Thursday");
break;
case 6:
System.out.println("Friday");
break;
case 7:
System.out.println("Saturday");
break;
default:
System.out.println("Unknown day");
break;
}
}
}
This first example is to print the name of the day of the week
given its number. It has seven cases, one for each day of the week,
and a default case for anything else. Every case ends with a break.
If you run this example, it will print out "Tuesday".
As for our second example, we will consider the game known as
"craps". The rules of craps are a bit involved, but the beginning roll,
also known as the "come out" roll are simple. Two dice are rolled,
and the result is determined according to their sum as follows:
switch (total) {
case 2:
case 3:
case 12:
System.out.println("Player loses!");
break;
case 7:
case 11:
System.out.println("Player wins!");
break;
case 4:
case 5:
case 6:
case 8:
case 9:
case 10:
80 programming with java
switch (total) {
case 2:
case 3:
case 12:
System.out.println("Player loses!");
break;
case 7:
case 11:
System.out.println("Player wins!");
case 4:
case 5:
case 6:
case 8:
case 9:
case 10:
System.out.println("On to second roll!");
break;
}
}
}
The break statement after the line that prints "Player wins!" has
been omitteed. If you run this, you will see the following output:
Player wins!
On to second roll!
switch (total) {
case 2, 3, 12:
System.out.println("Player loses!");
break;
case 7, 11:
System.out.println("Player wins");
break;
case 4, 5, 6, 8, 9, 10:
System.out.println("On to second roll!");
break;
}
}
}
switch (total) {
case 2, 3, 12 -> System.out.println("Player loses!");
case 7, 11 -> System.out.println("Player wins");
case 4, 5, 6, 8, 9, 10 -> System.out.println("On to second
roll!");
}
}
}
This introduces the so-called arrow operator ->. Having the arrow
operator implies just one thing is to be done, and that is it. No Do not go looking for the arrow key
more continuing down. on your keyboard! Believe it or not,
this has happened before. The arrow
What if I wanted to do more than one thing? Just for the sake of operator is just a minus sign follwed
the argument, let us say I wanted to print another line, saying "We by the "greater than" symbol.
are sorry." in case the player loses. Here is how you do it:
public class Main {
public static void main(String[] args) {
int total = 7;
switch (total) {
case 2, 3, 12 -> {
System.out.println("Player loses!");
System.out.println("We are sorry.");
}
case 7, 11 -> System.out.println("Player wins!");
What we did is, we combined the two lines into a single code
block. A code block is any number of statements enclosed in a pair
82 programming with java
of braces {}. You have seen blocks in multiple places already; the
new information here is that you can use them anywhere a statement
is expected. Any code block in Java also defines a scope. Any local
variables defined within a certain scope can only be accessed within
that scope. This is a case of "What happens in Vegas stays in Vegas".
Let us see what we mean by that with an example:
public class Main {
public static void main(String[] args) {
int total = 7;
switch (total) {
case 2, 3, 12 -> {
System.out.println("Player loses!");
System.out.println("We are sorry.");
}
case 7, 11 -> System.out.println("Player wins!");
switch (total) {
case 2, 3, 12 -> {
System.out.println("Player loses!");
System.out.println("We are sorry.");
}
case 7, 11 -> System.out.println("Player wins!");
This code will not compile. You will end up getting an error in
the last println statement, saying "Cannot resolve symbol total".
This is because the variable total was defined within the new
scope introduced, and is not available (visible to the compiler)
outside of the scope.
Exercises
The semicolons (";") are part of the structure of the for state-
ment.
86 programming with java
This "classic" for loop in its most typical usage, makes use of
an integer counter variable to repeat its body a pre-determined There is what is called a "for each"
number of times. To be sure this is not the only possibility, but this loop too. However we are not ready to
comprehend that yet.
kind of usage is behind the naming of the three parts.
The first part is the initializer. Here, the counter variable is given
its starting value with an assignment. As in our example, it is also
possible to declare the variable here, in which case its scope will be
the for loop.
Technically speaking, the initializer is executed once and only
once when execution reaches the for loop. It can be any kind of
statement, and is not limited to an assignment to a counter variable.
The second part is the condition. This is very similar to the condi-
tion of an if statement - it must be some expression that evaluates
to a boolean value. The loop body is repeatedly executed as long as
this value is true. The check is done before every execution, so it is
possible that the loop body is not executed at all.
The third part is the increment. Every time the execution of the
loop body is complete, the statement in the increment part is ex-
ecuted. Typically, this contains a statement that will update the
counter variable, although just like the initializer, it is not really
restricted - any kind of operation can be performed here.
So, here is how the computer executes a for loop:
• The loop body adds every value of i into a variable called sum.
The while loop is very similar to the for loop, except that it only
has the condition part. In other words, you can consider it to be an
if statement that keeps repeating.
The general form of the while loop is as follows: Of course, I am lying to you. The
braces are not really part of the form.
If the loop body is a single statement,
you do not need the braces. However, I
never use any loop without the braces,
and neither should you.
looping 87
while (<condition>) {
<loop body>
}
3 → 10 → 5 → 16 → 8 → 4 → 2 → 1
The conjecture is that, no matter what n > 1 you pick, the se-
quence will always reach 1. There no known exceptions, but there As of 2020, all numbers up to 268 have
is no proof for this either. been checked, as published by David
Barina.
Here is the code that will print the sequence utilizing a while
loop.
public class Main {
public static void main(String[] args) {
int n = 3;
System.out.println(n);
while (n != 1) {
if (n % 2 == 0) {
n = n/2;
} else {
n = 3*n + 1;
}
it will complete in the top line. This is, in fact, the reason for the
existence of the for loop.
The do while loop is the black sheep of the family. This is the kind
of loop that you will probably use the least, and see the least often
when you look at other people’s code. The general form of the do
while loop is as follows:
do {
<loop body>
} while(<condition>);
double x;
double y;
do {
x = random.nextDouble(-1.0, 1.0);
y = random.nextDouble(-1.0, 1.0);
} while (x*x + y*y > 1.0);
the right hand side, new is a Java keyword which is used for creat-
ing objects. The result is stored in a variable called random of type
Random.
Once we have created this Random object, it provides us with
many functionality involving random numbers. The following two
lines do exactly that:
x = random.nextDouble(-1.0, 1.0);
y = random.nextDouble(-1.0, 1.0);
looping 89
The break and continue statements work inside all three kinds of
loops. (Well, break is also used in the switch statement, which we
have already seen.)
if (i > 50) {
break;
}
}
}
}
if (i % 3 == 0) {
System.out.println(i);
}
}
}
}
Exercises
1000
∑ k4
k =1
n
n(n + 1)(2n + 1)(3n2 + 3n − 1)
∑ k4 = 30
k =1
I derived this formula when I was in
high school. Still in my memory.
looping 91
The following line of Java code will print the "correct" value,
using Java’s constant for π:
System.out.println(Math.PI*Math.PI/6.0);
x2 x3 x4
ln(1 + x ) = x − + − +···
2 3 4
The series is convergent for −1 < x ≤ 1, so it can be used
(marginally) to compute ln 2. This converges rather slowly, so in-
clude the first million terms to get an approximate value.
The following line of Java code will print the "correct" value,
using Java’s mathematics library to compute the natural logarithm
of 2.
System.out.println(Math.log(2));
Java contains two forms of the AND operator, & and &&. Both are
AND operators, and are binary operators, taking two boolean
operands. The result is also a boolean, and is true if both operands
are true. If at least one of the operands is false, the result is false.
if (y != 0 && x/y == 2) {
// Something happens here.
}
Java also contains two forms of the OR operator, | and ||. The
situation here is very similar to the case of the AND operator. The
OR operator takes two boolean operands, and results in true when
at least one of the operands is true. For the result to be false both
operands must be false.
Unless you know exactly what you are doing, the Conditional-Or
Operator || is the default one to use; and it is the one that you will
most often find in existing code.
The name x is a name for where the actual int value is in mem-
ory. The situation is not the same with a String (or any class, for
that matter). When you declare a String variable such as:
String s;
The name s is not a name for where the actual data of a String
is stored in memory. It is a name for a reference to a String object
where the actual data is stored.
If you are totally confused at this point, you are well within
your rights to get confused. This is rather hard to grasp without an
understanding of how the memory (by memory here we are talking
about RAM, Random Access Memory) of a computer works - or at
least understanding a rudimentary model of how it works. So we
will digress to understand that.
The big idea occurs when you realize the addresses are also num-
bers, and they could also be stored in memory! So, my integer
value is located in memory address 0x0010 and I could store that
value in another memory location, say, 0x0008. (From this point
on we will use little-endian byte order exclusively.) The state of
memory when this is done is shown in Figure 10.4.
When the address of another memory location is stored in mem-
ory rather than a value, this is called a pointer. Following that
string s 99
pointer value, that is, going and accessing the memory location
stored in the pointer value is called dereferencing that pointer.
The terms "pointer" and "dereferencing" are almost never used
in Java. You may also hear that "there are no pointers in Java". (You
might even believe that until you see your first NullPointerException.)
There are pointers in Java, but they are called something else. They
are called references.
Why give a different name to the same thing? The main rea-
son is that, lower level languages such as the C language, have
pointers. In such languages, you can have pointers to pointers, and
pointer arithmetic where you can modify the value of the pointers
themselves to point at different places in memory. This can be very
powerful, and at the same time very, very dangerous in the sense
that it may cause problems that are very hard to detect and fix.
For this (and other reasons, like garbage collected memory man-
agement) Java has no pointers. It has references, which are able to
store the location of objects, but there are no pointers to pointers or
pointer arithmetic. This new type of pointer with reduced function-
ality (and therefore much safer) is called a reference.
You can probably imagine the need where you need a pointer,
but you need it to "point at nowhere". It was decided that any
pointer that points at memory location zero "points nowhere" and
trying to dereference that pointer should be an error condition. A
pointer with a value of zero is known as a "null pointer".
Moving to the world of references in Java, the numeric nature of
pointers are fully hidden. The "points nowhere" value for references
is known as null and is a Java keyword, and it is not interchange-
able with the numeric value of zero.
Let us try to make sense out of all this. When we declare a
String variable we end up creating only a reference to a String
object. So, when we declare:
String s;
can create an object of any class by using the new keyword. Without
special treatment, our code fragment would look like the following:
String s;
s = new String("This is a string");
Creating Strings
Methods of String
length
The first method we will look at is length and below you can see
what the Java documentation says about it:
length
public int length()
Returns the length of this string. The length is equal to the num-
ber of Unicode code units in the string.
Specified by:
length in interface CharSequence
Returns:
the length of the sequence of characters represented by this object.
Once again, there are a few things in this documentation that are
not familiar. For now, do not worry about "interface" or CharSequence.
One thing that needs translation is "Unicode code units". This is a
(perhaps excessively) precise way of saying "characters". Here is a
code fragment showing how to use this method:
String s = "Hello, world!";
System.out.println(s.length());
charAt
Another important method is charAt:
charAt
public char charAt(int index)
Returns the char value at the specified index. An index ranges
from 0 to length() - 1. The first char value of the sequence is at
index 0, the next at index 1, and so on, as for array indexing. If
the char value specified by the index is a surrogate, the surrogate
value is returned.
Specified by:
charAt in interface CharSequence
Parameters:
index - the index of the char value.
string s 103
Returns:
the char value at the specified index of this string. The first char
value is at index 0.
Throws:
IndexOutOfBoundsException - if the index argument is negative or
not less than the length of this string.
System.out.println(firstCharacter);
System.out.println(lastCharacter);
String Comparison
if (a == b) {
System.out.println("The two Strings are equal.");
} else {
System.out.println("The two Strings are NOT equal.");
}
}
}
Now you are thinking, "Well, it works just fine! What is the prob-
lem?". The problem is that it works as expected, but for the wrong
reasons. We will circle back to why this seems to work. Here is the
next example you need to look at:
public class Main {
public static void main(String[] args) {
String a = "Hello";
String b = " world";
String c = "Hello world";
String d = a + b;
if (c == d) {
System.out.println("The two Strings are equal.");
} else {
System.out.println("The two Strings are NOT equal.");
}
}
}
You can actually check that the contents of the two Strings c and
d are exactly the same. However, checking for equality indicates
that they are not equal.
Why does this happen? This is because the == operator checks
for reference equality. That means, for the comparison to result in
a true value, the two Strings must be the same String living in
the same exact place in the computer memory. Strings residing in
different places would not be compared as equal by the == operator
even if their contents were identical.
Of course, what you usually want (and by usually we mean almost
always) is to check Strings for equality of content. How do you do
that in Java? The answer is, as is the answer for a lot of things, by
using a method. Here is the above example modified:
public class Main {
public static void main(String[] args) {
String a = "Hello";
String b = " world";
String c = "Hello world";
String d = a + b;
if (c.equals(d)) {
System.out.println("The two Strings are equal.");
} else {
System.out.println("The two Strings are NOT equal.");
}
string s 105
}
}
If you run this code with the changes, you get the following
output:
The two Strings are equal.
Exercises
if (isPalindrome) {
System.out.println(s + " is a palindrome.");
} else {
System.out.println(s + " is not a palindrome.");
}
}
}
(So just counting spaces and adding one will not work.)
For this, you should make use of the following method:
boolean Character.isWhitespace(char c)
So, you give it a char, and if it is whitespace, it returns true. In
this question, it is safe to define a word as anything separated by
any number of whitespace characters. (Note that punctuation is
always adjacent to the previous word, and is always followed by at
least one space. Or at least, we assume so for the purposes of this
quesiton.)
The outline of the program should look like:
public class Main {
public static void main(String[] args) {
String s = " Just go away, please! ";
int wordCount = 0;
n! = n × (n − 1) × (n − 2) × · · · × 3 × 2 × 1
x2 x3 x4
ex = 1 + x + + + ...
2! 3! 4!
108 programming with java
1 1 1
e = 1+1+ + + ...
2! 3! 4!
Write a computer program to compute e as a double. Make sure
it is correct to at least ten decimal places.
1 1 2 3 5 8 13 21 34 55 89 . . .
Exercise 11 Write a computer program to calculate ln 2. Note that From the first midterm examination,
there is a series expansion for the natural logarithm as follows: Fall 2022.
x2 x3 x4
ln(1 + x ) = x − + − ···
2 3 4
This series converges for −1 < x ≤ 1. For x = 1, we get a series
for ln 2:
1 1 1
ln(2) = 1 − + − ···
2 3 4
This is also known as the alternating harmonic series. Write a com-
puter program to compute the value of ln2 using the first 1000
terms of the series.
Exercise 12 Write a computer program to find the number of From the first midterm examination,
divisors of any positive integer. Fall 2022.
Exercise 13 Building up on the previous exercise, write a com- From the first midterm examination,
puter program that finds and prints out all four-digit integers that Fall 2022.
... you were calling the length() method of that specific String
instance. That is, the length() method made use of the contents
of the particular String containing "abc", and returned the value
of 3 to be printed on the screen. So, instance methods are always
connected to objects (explicitly or implicitly) created with the new
keyword. (Here the new is implicit, again due to special treatment of
the String class.)
On the other hand, static methods are not connected with any
object instance. They belong directly to the class. Our primary
example is the main method, which is a static method as is obvi-
ous from its declaration containing the static keyword. All static
methods are called in the form <class name>.<method name>() or
just using the method name if the call is done from within the same
class.
Before we attempt to write any static methods, let us use ex-
isting static methods from the Java library first. Our primary
example here is going to be Java Math class, which contains quite a
few static methods for mathematical computations.
The Math class is library class containing many methods for most
mathematical operations you can think of.
exp
public static double exp(double a)
Returns Euler’s number e raised to the power of a double value.
Special cases:
If the argument is NaN, the result is NaN.
If the argument is positive infinity, then the result is positive infin-
ity.
If the argument is negative infinity, then the result is positive zero.
If the argument is zero, then the result is 1.0.
110 programming with java
log
public static double log(double a)
Returns the natural logarithm (base e) of a double value. Special
cases:
If the argument is NaN or less than zero, then the result is NaN.
If the argument is positive infinity, then the result is positive infin-
ity.
If the argument is positive zero or negative zero, then the result is
negative infinity.
If the argument is 1.0, then the result is positive zero.
The computed result must be within 1 ulp of the exact result.
Results must be semi-monotonic.
Parameters:
a - a value
Returns:
the value ln a, the natural logarithm of a.
The point is that you can call all of these static methods in the
same way. The way you call a static method is as follows:
<class name>.<method name>(<arguments>)
The return type declares what the result of the method is go-
ing to be. The method name is the name you want to give your
method, which is very similar to a variable name; just as arbitrary
and just as important. The argument list is a comma separated list
of variable declarations, which represent the arguments that must
be supplied to the method while calling it.
Let us start with an example problem. Suppose we want to write
a program to calculate integer powers of integers, that is, ab . Up to
now, without static methods we would have written the program
as follows:
public class Main {
int pow = 1;
System.out.println(pow);
}
}
return pow;
}
112 programming with java
Let us examine what we have done here. The declaration line is:
public static int integerPower(int a, int b) {
This declaration line tells us that the name of the static method is
integerPower. The int to the left of the method name indicates that
the result of this method is going to be an integer. The argument
list, which is inside the paretheses to the right of the method name
indicates that this method takes two arguments, their names are a
and b and both arguments are of type int.
The body of the methodis the part that is between the opening
and closing braces after the argument list’s closing parenthesis. The
really new part here is the last statement, which reads:
return pow;
We just said that static methods are called in the form <class
name>.<method name>(<argument list>). According to that, our
call should have looked like the following:
System.out.println(Main.integerPower(3, 4));
Calling Conventions
increment(y);
System.out.println(y);
Exercises
Hint: You can concatenate a String and a char with the + opera-
tor.
gcd( a, b)
So, gcd(3, 5) = 1, gcd(10, 25) = 5, and gcd(125, 50) = 25.
114 programming with java
The square brackets after the int makes the type of the variable
called heights an int array rather than a regular int. And, int[] is
pronounced as "int array".
An array variable is a reference variable. As such, it is only a
name, and the actual object (which is an array here) must be created
using the new keyword. This is what is done on the right hand side
of the assignment with new int[40]. This creates an array of 40
integer variables, and makes the name heights a reference to it.
The general way to declare an array of any type is:
<type>[] <name>;
heights[0] = 175;
heights[1] = heights[0] + 2;
heights[39] = 162;
heights[40] = 0; // Error
heights[-1] = 0; // Error
Let us say you want to create an array of five integers, and assign
them the values 3, 5, 7, 11, 13. One way to do this is as follows:
int[] x = new int[5];
x[0] = 3;
x[1] = 5;
x[2] = 7;
x[3] = 11;
x[4] = 13;
Automatic Initialization
We have seen that with regular variables if you never give them an
initial value, they are marked as "having no value" and the compiler
will not let you use them. Just to remember, the following code
fragment will produce an error at compile time: It says "variable m might not have
been initialized".
int m;
System.out.println(m);
System.out.println(m[3]);
return sum;
}
Since the array carries it own length information with it I can write a
general method to sum the elements in the array.
You may be wondering what is a section about the for loop doing
in a chapter about arrays. Well, there is an enhanced version of the
for loop, which can only be used with collections, of which the
array is the simplest example.
If you examine the array summing example in the previous sec-
tion, you can see that the loop variable only exists because I want
118 programming with java
for (int x : a) {
sum += x;
}
return sum;
}
Note that the loop has been reduced. The operative line is:
for (int x : a) {
This line is read as "for each int x in a". So, what we are asking
the computer to do is to run the loop body for every element inside
the array a, and pass them one by one to the loop body. In the loop
body, for every iteration the variable x gets the next value from the
array.
It is a good idea to make use of the enhanced for loop any time
you can. There are specific times when you do not want to use
this; one common reason is because you need to make use of the
index (like printing) variable; and the enchanced for loop hides
that information.
Arrays in Java are reference types, but are not classes. As such,
there is a bunch of functionality that is designed to work with ar-
rays inside the Arrays class. All these are in the form of static
methods, similar to the case with the Math class static methods.
One important method is the sort method. This method takes In fact, this is a whole family of meth-
an array, and modifies the array in-place to put its elements into ods, since there is a method for each
numeric array type, plus there are
ascending order. The Java documentation states the following: variants that sort only ranges of the
given array.
sort
public static void sort(int[] a)
Sorts the specified array into ascending numerical order.
Implementation Note:
The sorting algorithm is a Dual-Pivot Quicksort by Vladimir
Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm offers
O(n log(n)) performance on all data sets, and is typically faster
than traditional (one-pivot) Quicksort implementations.
Parameters: a - the array to be sorted
arrays 119
If you look at any code used in practice, perhaps with the exception
of low-level number-crunching, nobody uses arrays any more. In-
stead, you will find a host of different classes from the Java library
used.
Studying the full extent of data structures, the algorithms that
go with these data structures, and their implementation in Java is
worth a full course on its own (almost always called "Data Struc-
tures and Algorithms"). Here, we will only examine the two Java
classes that provide "better" alternatives to using "bare" arrays;
ArrayList and LinkedList.
• The index always starts at zero, and goes to one less than the
length of the array.
Exercises
Exercise 1
Write a static method that takes an int array as an argument,
and returns the second largest element as an int. The array itself
must remain unmodified, and use of Arrays.sort() is not allowed.
Use the following template program:
public class Main {
public static void main(String[] args) {
int[] x = {6, 8, 9, 2, -1, 12, 5, 17, 3, 1, 7, 11};
Exercise 2
Write a static method that takes an int array as an argument,
and reports whether its elements can form a set, or not. This es-
sentially reports whether or not whether the array contains dupli-
cate elements. If the array does not contain duplicate elements, the
method should return true, indicating that it is a set. If the array
does contain duplicate elements, the method should return false,
indicating that is not a set.
Use the following template program:
public class Main {
public static void main(String[] args) {
int[] x = {6, 8, 9, 2, -1, 12, 5, 17, 3, 1, 7, 11};
int[] y = {6, 8, 9, 2, -1, 12, 5, 17, 9, 1, 7, 11};
return false;
}
}
14 Classes
When you want to define a new data type, you create a new class.
Any class goes into a file matching its name, as you already know.
So, we start by creating a new file Complex.java with the class
Complex inside it.
public class Complex {
Member Variables
Methods
z = x+i·y
q
| z | = x 2 + y2
So, we can now add a method to our complex class, to add func-
tionality to it. This is going to be a "regular", non-static method.
Here is the class after having added it:
public class Complex {
public double real;
public double imaginary;
System.out.println(u.magnitude());
}
}
If you run this here, you will find that it nicely prints 5.0 since
the magnitude of 3 + i · 4 is 5.
classes 125
z = x+i·y
z∗ = x − i · y
z = x+i·y
z = r · eiθ
x = r · cos θ
y = r · sin θ
Once again, the return value will be a number. So, here is what
the class looks like having added this method:
126 programming with java
System.out.println(magnitude * Math.cos(argument));
System.out.println(magnitude * Math.sin(argument));
}
}
3.0000000000000004
3.9999999999999996
It is quite close to the original real and imaginary parts, but not
exactly. Even though the precision is double numbers is good, real
computation always introduces some amount of error.
These are almost all of the things you can do with a single com-
plex number. Most of the meaning of complex numbers come from
binary operations on complex numbers - operations that operate on
two complex numbers.
The simplest of these is probably addition. The definition of
addition is simple:
classes 127
z = z x + i · zy
u = u x + i · uy
v = v x + i · vy
z = u+v
zx = ux + vx
zy = uy + vy
Complex z;
Complex z;
}
}
If you just type that in, it will not compile, because we did not
implement the method yet. What we intend to do is to write a
method called add which operates on two Complex objects, one
of them is the one the method "belongs" to, the other one will be
passed as an argument. The result will be another, new Complex
object. Here is the implementation:
128 programming with java
return sum;
}
}
When you type the new add method in, the Main class should
be compiling with no errors. Now, you can run it, and the result
would be:
11.0
19.0
z = z x + i · zy
u = u x + i · uy
v = v x + i · vy
z = u·v
z x = u x · v x − uy · vy
zy = u x · vy + uy · v x
return product;
}
z = z x + i · zy
u = u x + i · uy
v = v x + i · vy
u
z=
v
u · v∗
z=
v · v∗
u · v∗
z=
| v |2
This information should be sufficient to write the division
method. Here is one way to do this:
public Complex divide(Complex divisor) {
Complex z = multiply(divisor.conjugate());
z.real /= divisorMagnitude*divisorMagnitude;
z.imaginary /= divisorMagnitude*divisorMagnitude;
return z;
}
Complex z = u.divide(v);
}
}
130 programming with java
Constructors
public Complex() {
public Complex() {
return sum;
}
return sum;
}
This does exactly the same thing; strictly speaking, in this case
using this is unnecessary. However, I believe in making use of it,
since this notation makes it obvious we are talking about a member
variable, not a local variable or a parameter.
There is an important case where it is not only useful, but also
necessary. Consider the two-argument constructor we have written
for the Complex class:
public Complex(double x, double y) {
real = x;
imaginary = y;
}
You may think that this would not compile, but it will, gener-
ating just a warning. This is because while you are not allowed to
use a local variable name twice (method arguments count as local
variables) you are allowed to have a local variable and a member
variable of the same name. Then, what happens when you have
both, and use the variable name? Which one are you talking about?
The answer is that the local variable takes precedence. This is called
shadowing, when you declare a local variable with the same name
as a member variable, the member variable is shadowed by the local
variable.
Is there a way to reach beyond the shadow? Yes, this is easily
accomplished by the this reference variable. The constructor can be
fixed to work properly as follows:
public Complex(double real, double imaginary) {
this.real = real; // Works fine
this.imaginary = imaginary; // Works fine
}
z.real /= divisorMagnitude*divisorMagnitude;
z.imaginary /= divisorMagnitude*divisorMagnitude;
classes 133
return z;
}
The keyword public has been all over the place since the begin-
ning. It is actually what we call an access modifier. Marking some-
thing as public means pretty much that: It is accessible from any-
were in the program. We should really be saying any other class in
the program, since accessing methods or member variables from
within the same class is always possible.
One alternative to the public access modifier is the private
access modifier, which is exactly what it sounds like: Whatever you
apply it to (you can apply it to methods and member variables) can
only be accessed from within the same class, and nowhere else.
The big question is this: Why would we want to do this? The
answer, at its most fundamental is that we have limited brain ca-
pacity. A program typically contains many classes that interact with
one another. Every public part of a class is an interaction point,
leading to potential connections. We can not really remember and
track all such interactions easily, so we choose to reduce the possible
interactions, hopefully in a meaningful and orderly way.
What we call encapsulation is keeping the data safe from direct
modification from the outside world, allowing it to be only modi-
fied through well-defined means, which are the methods provided
in the class. We usually achieve this by making member variables
private, and allowing them to be accessed only through methods.
So, we change the top of our class to look like the following:
public class Complex {
private double real;
private double imaginary;
//...
}
Now, we can print the real and imaginary parts from the main
method as follows:
System.out.println(z.getReal());
System.out.println(z.getImaginary());
//...
}
Immutable Classes
are called immutable objects. The classes of these objects are mutable
classes.
In a class, if all your member variables are private, and you
have getters but no setters, and no additional methods that assign
values to member variables, that class is immutable.
Why is this important? Again, limited cognitive capacity. Lim-
iting the ways in which objects can be modified makes thinking of
the program functionality easier in a multitude of ways. One pri-
mary example of an immutable class in Java is the good old String.
Once a String object is created, there is no way of changing its
contents.
Recap
• A constructor has no return type and always has the same name
as the enclosing class – indeed, this is how the compiler recog-
nizes a constructor.
Exercises
Exercise 1
The following is a Point class, designed as part of a two-dimensional
geometry library. Note that it has been designed to be immutable:
package tr.edu.ozyegin.cs101.geometry2d;
y = m·x+n
a·x+b·y+c = 0
private double a;
private double b;
private double c;
/**
* Create a line with the equation ax + by + c = 0
*
* @param a the parameter a
* @param b the parameter b
* @param c the parameter c
*/
/**
* Create a line with the equation y = mx + n
*
* @param m slope of the line
* @param n y-intercept of the line
*/
public Line(double m, double n) {
this.a = m;
this.b = -1.0;
this.c = n;
}
/**
* Create a line that goes through both
* points p and q.
*
* @param p first point
* @param q second point
*/
public Line(Point p, Point q) {
// TO BE IMPLEMENTED
}
/**
* The parameter a for the equation ax + by + c = 0
*
* @return parameter a
*/
public double getA() {
return a;
}
/**
* The parameter b for the equation ax + by + c = 0
*
* @return parameter b
*/
public double getB() {
return b;
}
/**
* The parameter c for the equation ax + by + c = 0
*
* @return parameter c
*/
public double getC() {
return c;
}
138 programming with java
/**
* The slope of the line, m where y = mx + n
*
* @return m, the slope of the line
*/
public double getM() {
return -a/b;
}
/**
* The y-intercept of the line, n where y = mx + n
*
* @return n, the y-intercept of the line.
*/
public double getN() {
return -c/b;
}
/**
* Checks if given point p lies on this line or not.
* If it does, returns true. Otherwise, returns false.
*
* @param p the point to be checked
* @return true if p lies on this line
*/
return false;
}
/**
* Finds the intersection point of this line and
* the line other given as the parameter.
*
* Returns null if this line and the other line
* are parallel.
*
* @param other the other line
* @return the intersection as a Point, null if parallel
*/
return null;
}
}
points. This should work, since two points define a line. You can
assume that the two points are distinct.
public boolean goesThrough(Point p)
This method is used to check whether the line goes through the
given point. The method should return true if it does, and false if
it does not.
Note that it might be a good idea to introduce some tolerance
here. After all, it is possible that rounding errors may throw the
calculation off sufficiently so that the method returns false erro-
neously. On the other hand, what do we really mean by "going
through" when dealing with doubles? How close is close enough?
These are not easy questions to answer.
public Point intersection(Line other)
This should return the intersection point of this Line and the
other Line, provided as a parameter.
If the lines are parallel, it should return null.
Note that this can also suffer from precision problems when
trying to check for parallelism. Even if the two lines were meant to
be parallel, you might get an intersection at a very distant point.
Again, difficult questions to deal with.
Make sure your implementations work as specified by calling
them from a main() method.
15 Miscellanea
Packages
You already know that classes have names. Naming classes is al-
ready hard, but another difficulty comes into play when programs
written by different people (or groups of people) come together in
a program. What if our classes have the same name? For example, I
might have a class named Point in my code to represent a point in
three dimensional place, and you might have a class named Point
to represent a geographical point (a point on the surface of the
Earth).
It is in general possible for class names to clash, if all names were
to live in the same space – a collision, somewhere, sometime is all
but inevitable.
The generic name for the solution is introducing namespaces.
If everyone has their separate namespace, naming clashes can be
avoided entirely.
Java’s version of namespaces is called packages. Packages have a
bit more to them than just providing a namespace, though.
A package name looks something like:
tr.edu.ozyegin.cs101.geometry
You can see in Figure 15.1 that the file Point.java is directly un-
der the src folder of the project. This means that the file is phys-
ically in the default package. The default package has an empty
name, and is not declared at all at the top of the file – in other
words it is the package you end up using if you have no idea that
packages exist. Now, the physical location of the file means it is
in the default package, while the declaration says it belongs in
tr.edu.ozyegin.cs101.geometry. This is the cause of the error.
Every IDE out there provides means to create a Java package. So,
if I go and create the package I have already named tr.edu.ozyegin.cs101.geometry,
it will become visible in the user interface.
You can see the end result in Figure 15.2. The package is now
created, but the error will persist, since the Point class is not in
there yet. In almost every IDE there is, you can perform a drag-
drop on the class to move it to a different package. Once you do
that, the error should disappear, given we have typed everything
correctly so far.
You can see in Figure 15.3 that the package name we entered has
been automatically converted to a series of nested (one inside the
other) directories in the filesystem. When you write Java code, you
will be working almost exclusively with IDEs, and normally do not
need to care about where the actual files are stored; the IDE will
perform the task correctly. However, in some cases you may need to
find out where exactly your dear source files are (or need to be) and
this is how things work in Java.
Javadoc
Write section about Javadoc.
16 Advanced Exercises
Exercise 1
Write a (static) method that takes an uppercase English letter as
a char as its argument and returns its letter value in the game of
Scrabble as an int.
Scrabble letter values are as follows:
• 1 point - A, E, I, O, U, L, N, S, T, R.
• 2 points - D, G.
• 3 points - B, C, M, P.
• 4 points - F, H, V, W, Y.
• 5 points - K.
• 8 points - J, X.
• 10 points - Q, Z.
switch (n) {
case 1 -> faceName = "One";
case 2 -> faceName = "Two";
case 3 -> faceName = "Three";
case 4 -> faceName = "Four";
case 5 -> faceName = "Five";
case 6 -> faceName = "Six";
146 programming with java
System.out.println(faceName);
}
System.out.println(faceName);
}
System.out.println(faceName);
}
Exercise 2
Write a (static) method that takes a pattern (as a String) and a
word (also as a String) as arguments, and returns whether or not
the pattern matches the string.
The pattern may consist of uppercase English letters or the as-
terisk (’*’). The asterisk is a wildcard that can match any uppercase
English letter. Uppercase English letters can match only themselves.
The following are various patterns:
**A**
QU***
**R
The first pattern matches all five-letter words with the letter ’A’
in the middle. The second pattern matches all five-letter words
beginning with the letters ’QU’. The third pattern matches all three-
letter words ending with ’R’.
The word may consist of uppercase English letters only. It does
not matter whether it is an actual English word or not, just that it
consists only of uppercase English letters.
You can use the following code as a template (which also con-
tains tests for you).
public class PatternMatcher {
public static void main(String[] args) {
boolean result;
try {
result = match("---", "BREAK");
System.out.println("FAIL");
} catch (IllegalArgumentException e) {
System.out.println("SUCCESS");
}
}
This also makes use of the fact that the letters form one contigu-
ous block in the ASCII character set.
In case characters that should not exist are there, it makes sense
to throw an IllegalArgumentException. In fact, one of the tests in
the template code checks for this exception being thrown.
17 Exam Questions
When exam time comes, one question that worries students a lot,
and therefore I get asked a lot is "what kind of questions will there
be on the exam", or "what will the exam be like" in short.
My policy, as much as I can keep it up, is to make the exam
questions public. I am a firm defender of freedom of information,
and will never attempt to hide information from students (unless
my hand is forced - which has happened).
While writing this book, I also thought that just giving out the
questions is not good enough. There should also be solutions. That
is also not good enough. We need to have solutions, the rationale of
having asked that question in the first place, and my evaluation of
whether this was a good question to ask in retrospect.
Since I wish give the student the chance to try the problems
for themselves first, this chapter only contains the questions. The
answers to the questions, and all other information are in the next
chapter.
As they say, "Do not try to do everything at once", but I have
never been one to let others dictate what I can or cannot do. So,
here we go.
Question 1
The exam rules are as follows:
You are allowed to use the course book, any materials on your
computer, and your programming environment (IntelliJ Idea) for
this exam.
In principle, it is closed Internet and Google, but in case of panic
you may consult Google.
You can not contact another person by any means under any
circumstances during the exam. This is considered cheating.
It is also an Honor System exam.
Honor System:
1. I will not cheat off of anyone in this exam.
2. I will not permit anyone to cheat off of me in this exam.
Select one:
Question 2
Which of the following is not true for the Java programming lan-
guage?
Select one:
• The JRE (Java Runtime Environment) includes the JVM and Java
class libraries.
Question 3
Which of the following is not true about Java source code and
source structure?
Select one:
• The main method must look like public static void main(String[]
args)
• All Java source code must be put in files with a .java extension.
• The name of the file must match the name of the public class
contained in the file.
Question 4
The "default" integer type to use in a Java program, unless you have
reason to use something else is:
Select one:
• long
• byte
• short
• int
exam questions 151
Question 5
If I know I need to store integers from 0 to 1000, which is the small-
est integer type I can use?
Select one:
• long
• byte
• short
• int
Question 6
Which one of the following types can store the largest integer val-
ues exactly, without loss?
• float
• int
• double
Question 7
A binary number has 22 binary digits.
If converted to hexadecimal, how many hexadecimal digits will it
have?
• 4
• 5
• 6
• 7
• 8
Information
Consider the following program:
public class Main {
Question 8
What is the largest value that will get printed?
Select one:
• 19999999
• 20000000
• 16777216
• 20000001
• 2147483647
Question 9
How many times does the loop body execute?
Select one:
• 20000000
• 2000001
• 1999999
• 16777216
• It is an infinite loop.
Question 10
Mathematically, the natural logarithm of a number has a the follow-
ing series expansion:
2 3 4
ln(1 + x ) = x − x2 + x3 − x4 · · ·
This series does not converge for all values of x, but it does con-
verge for x = 1, giving a series for ln 2:
ln(2) = 1 − 21 + 13 − 14 · · ·
Write a program to compute the value of ln(2) as a double, using
the first 1000 terms of the series.
Do not attempt to use library methods. Also, your code should
only print the final computed value of ln(2) as its output.
Using more or less than 1000 terms of the series is considered to
be an error. Obeying specifications is important.
Paste your whole class into the space given below.
Question 11
Every positive integer n has divisors which can divide it exactly.
For example, the number 6 has 4 divisors:
1, 2, 3, 6
Prime numbers have exactly two divisors. Like 5 has 2 divisors:
1, 5
Write a Java program that will start with an integer, and find its
number of divisors, and print it on the screen.
The form of your code should be as follows:
exam questions 153
System.out.println(numDivisors);
}
}
Do not alter existing lines. Only add code where the comment is.
Your code should work for n=12, as well as any positive integer n.
Question 12
Write a Java program that will print out all four digit numbers with
exactly 22 divisors.
Question 1
The exam rules are as follows:
You are allowed to use the course book, any materials on your
computer, and your programming environment (IntelliJ Idea) for
this exam.
In principle, it is closed Internet, but in case of panic you may
consult the Internet.
You can not contact another person by any means under any
circumstances during the exam. This is considered cheating.
It is also an Honor System exam.
Honor System:
1. I will not cheat off of anyone in this exam.
2. I will not permit anyone to cheat off of me in this exam.
3. If I see anyone violating the above two rules, I will report
them to the assistants and/or professor.
Select one:
Question 2
Which of the following contain the Java compiler?
Select one or more:
• JDK
• JRE
• JVM
154 programming with java
Question 3
Which of the following contains the Java core libraries?
Select one or more:
• JDK
• JVM
• JRE
Question 4
If we know a number has 15 octal digits (in its octal representation),
what is the fewest hexadecimal digits it may have (in its hexadeci-
mal representation)?
Question 5
Take any 32-bit bit pattern.
First, interpret it as a two’s complement, signed integer value.
Next, interpret it as a IEEE-754 32-bit floating-point number.
Given both values are non-zero, and are actual numbers, the two
values will always have the same sign.
Select one:
• True
• False
Question 6
Consider the floating-point values
7.5 30.0 960.0
What fields do they differ in?
Select one or more:
• Sign
• Exponent
• Significand
Question 7
Consider the following 16-bit shorts in Java:
00000000 00101101 00000000 01011010 00000000 10110100 00000001
01101000
Check all that are true.
Select one or more:
• They form a geometric progression.
Question 8
In Java, taking a byte value, and either:
Dviding it by 2 eight times
or
Multiplying it by 2 eight times
always results in the same value.
Select one:
• True
• False
Information
Consider the following program:
public class Main {
public static void main(String[] args) {
double sumOfInverseCubes = 0.0F;
System.out.println(sumOfInverseCubes);
}
}
Question 9
Here is a transcript of my chat with ChatGPT:
———-
This Java program calculates the sum of the inverse cubes of the
integers from 1 to 1,000,000 using a for loop and the formula 1/(i*i*i).
The sum is stored in a double variable sumOfInverseCubes and is
printed using System.out.println().
The output of the program will be a double-precision floating-
point number, which represents the sum of the inverse cubes. It is
expected to be approximately equal to 1.2020569031595931. This
value is the sum of the infinite series 1 + 1/8 + 1/27 + 1/64 + ...,
which converges to a value known as Apéry’s constant. Its exact
value is currently unknown, but it is believed to be an irrational
number.
156 programming with java
——-
I tried it. It prints Infinity.
——-
Thank you for letting me know. The program indeed produces a
value that exceeds the maximum finite value that can be represented
by a double variable, which is approximately 1.7976931348623157
× 10ˆ308. This occurs because the sum of inverse cubes converges
very slowly. When a double variable overflows, it is set to positive
or negative infinity, depending on the sign of the value. In this case,
since the sum is positive, the program prints Infinity.
Is ChatGPT correct?
Select one:
• True
• False
Question 10
Consider modifying the number of terms used in the calculation,
which is 1,000,000 terms in the first form of the program.
For example, we can try taking only 100 terms as in the follow-
ing program:
public class Main {
public static void main(String[] args) {
double sumOfInverseCubes = 0.0F;
System.out.println(sumOfInverseCubes);
}
}
Question 11
Modify the given program to create a fixed version that works well
even with a million terms.
Your changes to the code should be minimal. If you submit
totally new code, you will get no points.
Paste the complete class below:
Information
A salesman works on commission.
When asked how much he earns on a sale, he explains it as fol-
lows:
exam questions 157
"All my sale prices are whole numbers. I like whole numbers, and
never settle for any fractions.
If the sale amount is divisible by seven, my commision is two
sevenths of the sale amount.
If the sale amount is divisible by five, my commission is one fifth
of the sale amount.
If the sale amount is divisible by eleven, my commission is three
elevenths of the sale amount.
If two or more of the above happen, I my commission is the
largest possible, but I can not get two commissions on one sale.
And if none of the above happen, I get no commission at all."
"Well, I never know because I spend them as soon as I earn them. But
I remember this:
The largest sale amount I had was 1000, and there was only one of
that.
There were 2 sales of 999 each. 3 sales of 998 each; and this went
just like this all the way down. The least sales amount I had was 550,
and I can not remember how many of that happened, but I am sure
you can figure that out, being a computer scientist and everything."
Question 12
Write a Java program to compute the total commission the salesman
earned in the last year.
Question 13
Run your program, and obtain the result.
How much commission did he earn last year?
Information
The following program has been written:
public class Main {
public static void main(String[] args) {
int sum = 0;
System.out.println(sum);
}
}
Question 14
Here is a transcript of my chat with ChatGPT:
——–
There is no mistake in the program. It correctly calculates the sum
of the fourth powers of the integers from 1 to 120, and prints the
result.
Is ChatGPT correct?
Select one:
• True
• False
Question 15
Calculate the sum of fourth powers of integers from 1 to 120.
(If you think ChatGPT is correct, you can just run the program. If
you think ChatGPT is wrong, fix the program first.)
Information
Consider the following program:
public class Main {
Question 16
How many numbers does the program print?
Question 17
What is the sum of the numbers the program prints?
exam questions 159
Question 18
Consider the following program:
public class Main {
public static void main(String[] args) {
float sum = 0.0F;
float fraction = 0.25F;
if (sum == 1000*fraction) {
System.out.println("Equal");
} else {
System.out.println("Different");
}
}
}
• 0.1
• 0.2
• 0.25
• 0.4
• 0.5
18 Solutions to Exam Questions
Question 1
The exam rules are as follows:
You are allowed to use the course book, any materials on your
computer, and your programming environment (IntelliJ Idea) for
this exam.
In principle, it is closed Internet and Google, but in case of panic
you may consult Google.
You can not contact another person by any means under any
circumstances during the exam. This is considered cheating.
It is also an Honor System exam.
Honor System:
1. I will not cheat off of anyone in this exam.
2. I will not permit anyone to cheat off of me in this exam.
Select one:
Discussion
This is always the first question in my exams. When exams are
done on paper, the practice is to make students write down "Honor
System is observed" on their exam paper and get them to sign it.
When things happen on the computer, this seemed to be the correct
way to go.
Solution
Technically speaking, there is no correct answer here. And, there
is no grade associated with this question. The whole point of being
"honorable" is doing the right thing regardless of apparent short
162 programming with java
Retrospect
In retorspect, I find that putting this question at the beginning of
every exam is helpful, as a reminder of the importance of doing the
right thing. Yorgo İstafanopulos, or with his full
title Prof. Dr. Yorgo İstafanopulos,
The original form of the Honor System, as I first heard and saw
is one of the legendary professors
it applied by Yorgo İstefanopulos has three point rather than two, of Boğaziçi University of my time
the third point being: there as a student (and later Işık
University). He was a great influence
3. If I see anyone cheating, I will report them. on me, showing me what is possible,
I found this rather unsettling - making people responsible for and what the right approach is for
their own actions is one thing, making them responsible for the ac- engineering.
tions of other is... Something else. So, I removed this part, reducing
the Honor System to the format above.
Now I understand that what I have done is not helpful. Peo-
ple must be responsible for what they are doing first, that is quite
correct. However, they should also be responsible for their sur-
roundings, and beyond. The professor is not a police officer, and
the burden of maintaining an honorable environment should be
shared between the student body and the professor.
In addition, a lot of students just complain anonymously when
they see people cheating, shifting the burden to the professor in-
stead of doing something about it themselves. All in all, I have
decided that I am going to restore the Honor System to its full form
looking forward.
Question 2
Which of the following is not true for the Java programming lan-
guage?
Select one:
• The JRE (Java Runtime Environment) includes the JVM and Java
class libraries.
Discussion
This question is meant to be an easy question. Like other ques-
tions of this type, if you have understood what Java is, and how it
solutions to exam questions 163
Solution
The statement that is false here is "Running Java code on a differ-
ent platform requires recompiling the Java source code." The Java
compiler compiles source code into bytecode, which can be run
without modification on any platform having a JVM.
Retrospect
As an intended "easy question", it did its job pretty well. Most
people got this right.
ChatGPT can solve this problem.
Question 3
Which of the following is not true about Java source code and
source structure?
Select one:
• The main method must look like public static void main(String[]
args)
• All Java source code must be put in files with a .java extension.
• The name of the file must match the name of the public class
contained in the file.
Discussion
This one is another easy question. The main thing that the stu-
dent needs to know to answer this question is the fact that every-
thing in Java goes into a class, and Java is known as "the kingdom
of nouns". "Everything goes into a class" is not strictly true, how-
ever any other "top level" stuff is at the lowest level some form of
class.
Solution
The false statement is the first one: "A method can be written
outside of a class in Java source file." All methods have to go into a
class.
Interestingly enough, ChatGPT gets this question wrong. It even
provides an (incorrect) example of Java code with a method outisde
of a class.
Retrospect
Good enough. Most people got this question right, as intended.
164 programming with java
Question 4
The "default" integer type to use in a Java program, unless you have
reason to use something else is:
Select one:
• long
• byte
• short
• int
Discussion
This is a question that is borderline between Java design and
conventions. There is nothing preventing a programmer from using
a long for everything, for instance. However, when using libraries
this may become hard to use. Using a short can also cause prob-
lems and require additional care. If the student has been listening
at all in class, this is easy to answer.
Solution
The default integer type, even obvious by name, is int.
Retrospect
Good, simple question. Perhaps a bit "too easy", since this can
be answered only by just having listened partially in class, or just
having looked over the example code.
Question 5
If I know I need to store integers from 0 to 1000, which is the small-
est integer type I can use?
Select one:
• long
• byte
• short
• int
Discussion
This is one level harder, and meant to test knowledge in prac-
tice. However, it is not really meant as an "evil" question, since the
number given falls cleanly between limits, and not close to them.
Solution
A byte goes only up to 127, so it is not large enough. A short
can store a maximum of 32767, so it is large enough. The correct
answer is short.
solutions to exam questions 165
Retrospect
Good question, with potential to be re-used with different num-
bers, even if the actual answer remains the same. Making the cor-
rect answer a long would make the hardest question, especially if
the value limit is close to the variable limit.
Question 6
Which one of the following types can store the largest integer val-
ues exactly, without loss?
• float
• int
• double
Discussion
This is one question that requires better understanding of data
types. The float and double data types store floating-point num-
bers, they have great range, but limited precision. An int is for
integers, and stores everything it can exactly.
Solution
An int variable has 32 bits, and has the range of 31 bits, since
one bit is effectively used to store the sign.
A float variable also has 32 bits, but uses 23 bits to store the
significand. So, it is more limited than int values.
On the other hand, a double variable has 64 bits, and uses 52 of
these bits to store the significand. This is larger than 32, so it can
store larger integers than int exactly. This makes double the correct
answer.
Retrospect
In retrospect, this is a very good selective question. The answer
to the question is not a matter of opinion or convention, and can
be demonstrated. A good understanding enables a quick answer,
whereas a lack of understanding makes this nigh-impossible to
answer.
Variants are also possible, so this question can be asked again in
different forms.
Question 7
A binary number has 22 binary digits.
If converted to hexadecimal, how many hexadecimal digits will it
have?
• 4
• 5
166 programming with java
• 6
• 7
• 8
Discussion
I came up with this question instead of asking a regular con-
version problem. The purpose is to make the required calculation
simpler, while making the required understanding greater. The key
knowledge being tested here is that every four bits (binary digits,
that is) correspond to one hexadecimal digit.
Solution
If a binary number has 22 digits, since every four bits will re-
quire a hexadecimal digit, it will have 22/4=5.5 digits. This means
it will not fit into five hexadecimal digits, and will spill to the sixth
digit, but will definitely not exceed the sixth digit. So, the answer is
plain 6.
Retrospect
In retrospect, this is a good question - it asks about the rationale
behind the existence of hexadecimal numbers (or their utilization).
If you have an understanding, the answer can just be computed
with a division operation, rounded up.
Information
Consider the following program:
public class Main {
Discussion
This is a multi-part question, which is done by making an "in-
formation" part first, and then asking multiple questions about it.
The key point here is that a float variable is being used as the loop
variable, rather than the obvious int.
I expect the student to guess that something fishy is going on
at this point. If everything went exactly how they look, this would
have been a rather simple-to-answer question. As a general rule
(though not always adhered to) questions go from easy to hard as
the examination progresses. So, a problem this easy should not be
here.
solutions to exam questions 167
Solution
This is the information part, but the part that you need to "get"
here is the fact that a float can not hold integers larger than "sixteen
million something" exactly, and it will lose precision. Something
strange is bound to happen here.
Retrospect
This question as a whole stresses the fact that floats are not
magic, and if you try to use them without thinking instead of inte-
ger variables of the appropriate size, unexpected behavior can be
the result.
Question 8
What is the largest value that will get printed?
Select one:
• 19999999
• 20000000
• 16777216
• 20000001
• 2147483647
Discussion
Well, if "everything was working as usual", the answer would
have been 19999999, since the loop condition says that x is less than
twenty million. But nothing is working as usual, so the correct
answer is not that.
Note that it is possible to solve this question by copying the code
into your programming environment and running it.
Solution
If you just run the code, and wait for a while (it needs to print
millions of values, but it does not take more than a couple of min-
utes), you can see that things run normally for a while, but then the
value 16777216 gets printed repeatedly.
This is the correct answer. The reason is that, this number,
16777216 is actually 224 , which is 0b1000000000000000000000000,
that is a 1 followed by 24 zeros. In a float, you skip the leading
1, and store the rest in 23 bits. So, the last bit (rightmost bit) can
not be stored. When you add 1 to this number, you (would) get
16777217 which is 0b1000000000000000000000001, but since the fi-
nal bit still does not fit, the 1 at the end is dropped, and the stored
number is still 16777216. So, in the loop, no matter how many times
you add 1, it keeps printing the same number.
Retrospect
168 programming with java
Question 9
How many times does the loop body execute?
Select one:
• 20000000
• 2000001
• 1999999
• 16777216
• It is an infinite loop.
Discussion
After the previous question, this is rather obvious. However, if
you got the previous question wrong, you are very likely to get this
question wrong, too. If you actually bothered to run the code, you
know the answer already.
Solution
Well, due to reasons explained in the solution to the previous
problem, this code never stops running. It is a bit of a trick ques-
tion, and the correct answer is "It is an infinite loop".
Retrospect
In retrospect, having two questions here with very strong corre-
lation is not that great. However, I think the option "It is an infinite
loop" in this question is an additional hint to the student that some-
thing fishy may be going on.
Question 10
Mathematically, the natural logarithm of a number has a the follow-
ing series expansion:
2 3 4
ln(1 + x ) = x − x2 + x3 − x4 · · ·
This series does not converge for all values of x, but it does con-
verge for x = 1, giving a series for ln 2:
ln(2) = 1 − 21 + 13 − 14 · · ·
Write a program to compute the value of ln(2) as a double, using
the first 1000 terms of the series.
solutions to exam questions 169
Discussion
This is the first question in the exam where writing code is re-
quired. As such, it is the computation of a pretty straightforward
series; a Google search would very easily produce code that could
at least be of partial use here.
The question even states the exact series to be calculated, rather
than just giving the general formula (which the Taylor series for
ln(1 + x )).
Also, rather than requesting convergence, a fixed number terms
is asked for. And, that part is strict, and there is a warning about
obeying specifications, because if you are asked to use 1000 terms
for calculation, you are not allowed to use 10,000 terms, and say
you did better.
Solution
Here is one possible solution:
public class Main {
public static void main(String[] args) {
double ln2 = 0;
double sign = 1.0;
System.out.println(ln2);
}
}
System.out.println(ln2);
}
}
Retrospect
Not a bad question, but perhaps not a great one, either. The
good part is that you either have to figure out how to do sign flip-
ping with every term, or use an if/else inside the for properly.
The bad part is once again, very similar code can be found directly.
Interestingly, ChatGPT writes code for this, but ends up calcu-
lating ln(1/2) rather than ln(2). And, in the code it uses library
methods, and includes a lot of unnecessary variables and code.
Question 11
Every positive integer n has divisors which can divide it exactly.
For example, the number 6 has 4 divisors:
1, 2, 3, 6
Prime numbers have exactly two divisors. Like 5 has 2 divisors:
1, 5
Write a Java program that will start with an integer, and find its
number of divisors, and print it on the screen.
The form of your code should be as follows:
public class Main {
System.out.println(numDivisors);
}
}
Do not alter existing lines. Only add code where the comment is.
Your code should work for n=12, as well as any positive integer n.
Discussion
This question is rather simple to express. The goal is just to find
the number of divisors of an integer, and print it on the screen.
However, a lot needs to be told and shown to make sure it is under-
stood correctly, and the resulting code is in the correct format.
This question also forms a pair with the next one; solving this
question is part of the solution of the next problem.
solutions to exam questions 171
Solution
What is really expected here is a simple solution; the idea is to
try every integer k such that 1 ≤ k ≤ n and try each one. This is a
rather simple for loop application.
public class Main {
System.out.println(numDivisors);
}
}
Retrospect
This is not a bad question, yet again it is susceptible to finding
example code on the Internet. ChatGPT is also able to write good
code. However, such code normally contains more advanced solu-
tions. But, it is possible to prompt ChatGPT to write this kind of
code by telling it to rewrite the code without using square root.
Question 12
Write a Java program that will print out all four digit numbers with
exactly 22 divisors.
Discussion
This is more or less a continuation of the previous question.
Given you have been able to write code to count the number of
divisors of a number, then half of your work here is done. However,
if you have not, you are unlikely to be able to solve this problem.
This question is also purposefully expressed in short form, with-
out examples. This is intended to be one of the discriminatory
questions.
Solution
What we need to do here is to loop over all four digit numbers.
That means looping from 1000 to 9999. Then, we need to use the
code in the previous question to count the number of divisors of
each number, and if the calculated number of divisors is exactly 22,
we print the number in question.
172 programming with java
if (numDivisors == 22) {
System.out.println(n);
}
}
}
}
Retrospect
Good question, sharing the weakness that close solutions can be
found on Google, and ChatGPT can be prompted to write this exact
code.
In retrospect, asking questions requiring students to submit code
creates a lot of work reading and grading the solutions. Also, there
is a lot of questions from students asking why they did not score
the points they thought they should.
Towards the future, I intend to ask for larger code pieces in fewer
questions that should be sufficient to grade the coding style of
the student. Anything else should in the "proof-of-work" format,
containing original problems that ChatGPT will be mostly useless.
19 Projects
• I split the class into groups of five students each. I do this fully
randomly.
• I do not provide any help about how they are supposed to get a
hold of each other.
• I do not care who does the actual work within the group. They
all get the same grade.
interested in learning.
• The project should ultimately show the students that they can
actually do more than they think they can do.
are in the code but are in the wrong position in the guess. For this
example guess, the feedback would be:
0, 3
There are no direct hits, that is, no digits match exactly between
the code and the guess. There is a zero in the wrong place, and
there are two ones in the wrong place. This makes a total of three
indirect hits.
The code breaker tries to take advantage of the information from
the feedback, and produces another guess:
223344
Now, the feedback is:
1, 1
This is because 3 is a direct hit and there is an indirect hit for 4.
The game ends when the feedback is:
6, 0
Required Work
Analysis
You should perform an analysis of the problem, and write it up.
Specifically, you should explain what kind of algorithm you are
using, and how efficient you think it is. Proofs are not necessary
but would be appreciated.
Design
Once you have analyzed the problem and come up with an al-
gorithm, you should document your implementation design. What
176 programming with java
components your program will have, why and how it will be orga-
nized.
The Program
You can write your code in any IDE of your choice, but the pre-
ferred IDE is IntelliJ IDEA. Clean and clear code is important, as is
obeying naming and coding conventions observed throughout the
course.
The Presentation
You should be well prepared as a team to present your analysis,
design, program, and perform a demonstration in 15 minutes.
15 minutes will be a sharp cut-off point. Anything you have not
presented in the allotted 15 minutes is nonexistent.
projects 177
• 1 point - A, E, I, O, U, L, N, S, T, R.
• 2 points - D, G.
• 3 points - B, C, M, P.
• 4 points - F, H, V, W, Y.
• 5 points - K.
• 8 points - J, X.
• 10 points - Q, Z.
• Words do not have fixed values. If blank tiles are used, no points
are earned for those points.
Enter your hand. At most seven tiles, use _ for blank tiles.
TROUNG_
Enter the pattern to match. Use * for tiles you will place.
*****G
------
7 : DUGONG
7 : GORING
7 : GUNONG
7 : URGING
6 : OUTING
6 : OUTRIG
6 : ROTANG
6 : STRONG
6 : STRUNG
6 : THRONG
6 : UNTRIG
Required Work
Analysis
You should think about how to handle the problems in this
project. Specifially, consider the problem of blank tiles being used
as wildcards.
Design
Once you have analyzed the problem and come up with an al-
gorithm, you should document your implementation design. What
components your program will have, why, and how it will be orga-
nized.
projects 179
The Program
You can write your code in any IDE of your choice, but the pre-
ferred IDE is IntelliJ IDEA. Clean and clear code is important, as is
obeying naming and coding conventions observed throughout the
course.
The Presentation
You should be well prepared as a team to present your analysis,
design, program, and perform a demonstration in 15 minutes.
15 minutes will be a sharp cut-off point. Anything you have not
presented in the allotted 15 minutes is nonexistent.