Simple Java 1
Simple Java 1
Program Creek
CONTENTS
freface
ii
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
java questions
6
simple java pdf download
7
what can we learn from java helloworld?
8
how to build your own java library?
13
when and how a java class is loaded and initialized?
15
how static type checking works in java?
18
java double example
20
diagram to show java strings immutability
21
the substring() method in jdk 6 and jdk 7
23
why string is immutable in java ?
27
create java string using or constructor?
29
string is passed by reference in java
31
start from length & length() in java
34
how to check if an array contains a value in java efficiently?
what exactly is null in java?
39
comparable vs comparator in java
41
java equals() and hashcode() contract
46
overriding vs. overloading in java
49
what is instance initializer in java?
52
why field cant be overridden?
54
inheritance vs. composition in java
56
java enum examples
62
4 types of java inner classes
64
what is inner interface in java?
67
constructors of sub and super classes in java?
70
java access level for members: public, protected, private
73
when to use private constructors in java?
74
2 examples to show how java exception handling works
75
diagram of exception hierarchy
77
java read a file line by line a s how many ways?
80
how to write a file line by line in java?
82
fileoutputstream vs. filewriter
84
should .close() be put in finally block or not?
85
how to use java properties file?
87
monitors a s the basic idea of java synchronization
89
how to make a method thread-safe in java?
92
36
Contents
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Program Creek
Part I
F R E FA C E
Contents
The creation of Program Creek is inspired by the saying that Every developer should have a blog."
The word creek" is picked because of the beautiful scenes of Arkansas which is a central state of
America where I studied and worked 3 years. The blog has been used as my notes to track what
I have done and my learning experience. Unexpectedly, millions of people have visited Program
Creek since I wrote the first post 5 years ago.
The large amount of traffic indicates a more important fact other than that my writing skill is
good(which is totally the opposite): Developers like to read simple learning materials and quick
solutions. By analyzing the traffic data of blog posts, I learned which ways of explaining things are
preferred by developers.
Many people believe in no diagram no talk. While visualization is a good way to understand
and remember things, there are other ways to enhance learning experience. One is by comparing
different but related concepts. For example, by comparing ArrayList with LinkedList, one can better
understand them and use them properly. Another way is to look at the frequently asked questions.
For example, by reading Top 10 methods for Java arrays, one can quickly remember some useful
methods and use the methods used by the majority.
There are numerous blogs, books and tutorials available to learn Java. A lot of them receive large
traffic by developers with a large variety of different interests. Program Creek is just one of them.
This collection might be useful for two kinds of people: first, the regular visitors of Program Creek;
second, developers who want to read something in a more readable format. Repetition is key of
learning any programming languages. Hopefully, this contributes another non-boring repetition for
you.
Since this collection is 100% from the blog, there is no good reason to keep two versions of it. The
PDF book is converted automatically from the original blog posts. Every title in the book is linked
back to the original blog. When it is clicked, it opens the original post in your browser. If you find
any problem, please go to the post and leave your comment there. As it is an automatic conversion,
there may be some format problem. Please leave your comment if you find one. You can also contact
me by email: [email protected]. Thank you for downloading this PDF!
Chrismas Day 2013
Program Creek
Part II
J AVA Q U E S T I O N S
1
S I M P L E J AVA P D F D O W N L O A D
2
W H AT C A N W E L E A R N F R O M J AVA H E L L O W O R L D ?
This is the program every Java programmer knows. It is simple, but a simple start can lead to deep
understanding of more complex concepts. In this post I will explore what can be learned from this
simple program. Please leave your comments if hello world means more to you.
HelloWorld.java
public c l a s s HelloWorld {
/
@param a r g s
/
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
/ / TODO Auto g e n e r a t e d method s t u b
System . out . p r i n t l n ( " Hello World " ) ;
}
}
2.1
Java programs are built from classes, every method and field has to be in a class. This is due to
its object-oriented feature: everything is an object which is an instance of a class. Object-oriented
programming languages have a lot of advantages over functional programming languages such as
better modularity, extensibility, etc.
2.2
The "main" method is the program entrance and it is static. "static" means that the method is part
of its class, not part of objects.
Why is that? Why dont we put a non-static method as program entrance?
If a method is not static, then an object needs to be created first to use the method. Because the
method has to be invoked on an object. For the entrance purpose, this is not realistic. We can not
get an egg without a chicken. Therefore, program entrance method is static.
The parameter "String[] args" indicates that an array of strings can be sent to the program to help
with program initialization.
2.3
bytecode of helloworld
To execute the program, Java file is first compiled to java byte code stored in the .class file. What
does the byte code look like? The byte code itself is not readable. If we use a hex editor, it looks like
the following:
We can see a lot of opcode(e.g. CA, 4C, etc) in the bytecode above, each of them has a corresponding
mnemonic code (e.g., aload_0 in the example below). The opcode is not readable, but we can use
javap to see the mnemonic form of a .class file.
"javap -c" prints out disassembled code for each method in the class. Disassembled code means the
instructions that comprise the Java bytecodes.
j a v a p c l a s s p a t h .
c HelloWorld
Program Creek
8:
return
The code above contains two methods: one is the default constructor, which is inferred by the
compiler; the other is the main method.
Below each method, there are a sequence of instructions, such as aload_0, invokespecial #1, etc.
What each instruction does can be looked up in Java bytecode instruction listings. For instance,
aload_0 loads a reference onto the stack from local variable 0, getstatic fetches a static field value
of a class. Notice the "#2" after getstatic instruction points to the run-time constant pool. Constant
pool is one of the JVM run-time data areas. This leads us to take a look at the constant pool, which
can be done by using "javap -verbose" command.
In addition, each instruction starts with a number, such as 0, 1, 4, etc. In the .class file, each method
has a corresponding bytecode array. These numbers correspond to the index of the array where
each opcode and its parameters are stored. Each opcode is 1 byte long and instructions can have 0
or multiple parameters. Thats why these numbers are not consecutive.
Now we can use "javap -verbose" to take a further look of the class.
j a v a p c l a s s p a t h . verbose HelloWorld
Compiled from " HelloWorld . j a v a "
public c l a s s HelloWorld extends j a v a . lang . O b j e c t
S o u r c e F i l e : " HelloWorld . j a v a "
minor v e r s i o n : 0
major v e r s i o n : 50
Constant pool :
c o n s t #1 = Method
#6.#15; / /
j a v a / l a n g / O b j e c t ." < i n i t > " : ( ) V
c o n s t #2 = F i e l d
#16.#17;
//
j a v a / l a n g / System . o u t : L j a v a / i o /
PrintStream ;
c o n s t #3 = S t r i n g
#18;
//
H e l l o World
c o n s t #4 = Method
#19.#20;
//
java / io / PrintStream . println : ( Ljava /
lang / String ; )V
c o n s t #5 = c l a s s
#21;
//
HelloWorld
c o n s t #6 = c l a s s
#22;
//
java / lang / Object
c o n s t #7 = Asciz
< i n i t >;
c o n s t #8 = Asciz
( )V;
c o n s t #9 = Asciz
Code ;
c o n s t #10 = Asciz
LineNumberTable ;
c o n s t #11 = Asciz
main ;
c o n s t #12 = Asciz
( [ Ljava/lang/ S t r i n g ; ) V ;
c o n s t #13 = Asciz
SourceFile ;
c o n s t #14 = Asciz
HelloWorld . j a v a ;
c o n s t #15 = NameAndType # 7 : # 8 ; / / "< i n i t > " : ( ) V
c o n s t #16 = c l a s s
#23;
//
j a v a / l a n g / System
c o n s t #17 = NameAndType # 2 4 : # 2 5 ; / /
out : Ljava / i o / PrintStream ;
c o n s t #18 = Asciz
Hello World ;
c o n s t #19 = c l a s s
#26;
//
java / io / PrintStream
c o n s t #20 = NameAndType # 2 7 : # 2 8 ; / /
p r i n t l n : ( Ljava / lang / String ; )V
c o n s t #21 = Asciz
HelloWorld ;
c o n s t #22 = Asciz
j a v a /lang/ O b j e c t ;
c o n s t #23 = Asciz
j a v a /lang/System ;
Program Creek
10
const
const
const
const
const
#24
#25
#26
#27
#28
=
=
=
=
=
Asciz
Asciz
Asciz
Asciz
Asciz
out ;
Ljava/ i o / P r i n t S t r e a m ; ;
java/io/PrintStream ;
println ;
( Ljava/lang/ S t r i n g ; ) V ;
{
public HelloWorld ( ) ;
Code :
S t a c k =1 , L o c a l s =1 , A r g s _ s i z e =1
0:
aload_0
1:
invokespecial
# 1 ; / / Method j a v a / l a n g / O b j e c t ." < i n i t > " : ( ) V
4:
return
LineNumberTable :
line 2: 0
From JVM specification: The run-time constant pool serves a function similar to that of a symbol
table for a conventional programming language, although it contains a wider range of data than a
typical symbol table.
The "#1" in the "invokespecial #1" instruction points to #1 constant in the constant pool. The constant
is "Method #6.#15;". From the number, we can get the final constant recursively.
LineNumberTable provides information to a debugger to indicate which line of Java source code
corresponds to which byte code instruction. For example, line 9 in the Java source code corresponds
to byte code 0 in the main method and line 10 corresponds to byte code 8.
If you want to know more about bytecode, you can create and compile a more complicated class to
take a look. HelloWorld is really a start point of doing this.
2.4
Now the question is how JVM loads the class and invoke the main method?
Before the main method is executed, JVM needs to 1) load, 2) link, and 3) initialize the class. 1) Loading brings binary form for a class/interface into JVM. 2) Linking incorporates the binary type data
into the run-time state of JVM. Linking consists of 3 steps: verification, preparation, and optional
Program Creek
11
resolution. Verification ensures the class/interface is structurally correct; preparation involves allocating memory needed by the class/interface; resolution resolves symbolic references. And finally
3) initialization assigns the class variables with proper initial values.
This loading job is done by Java Classloaders. When the JVM is started, three class loaders are
used:
Bootstrap class loader: loads the core Java libraries located in the /jre/lib directory. It is a part
of core JVM, and is written in native code.
Extensions class loader: loads the code in the extension directories(e.g., /jar/lib/ext).
System class loader: loads code found on CLASSPATH.
So HelloWorld class is loaded by system class loader. When the main method is executed, it will
trigger loading, linking, and initialization of other dependent classes if they exist.
Finally, the main() frame is pushed into the JVM stack, and program counter(PC) is set accordingly.
PC then indicates to push println() frame to the JVM stack. When the main() method completes, it
will popped up from the stack and execution is done.
Program Creek
12
3
H O W T O B U I L D Y O U R O W N J AVA L I B R A R Y ?
Code reuse is one of the most important factors in software development. It is a VERY good idea
to put frequently-used functions together and build a library for yourself. Whenever some method
is used, just simply make a method invocation. For Java, its straightforward to manage such a
library. Here a simple example in Eclipse. The library will contain only one "add" method for demo
purpose.
Step 1: Create a "Java Project" named as "MyMath", and a simple "add" method under "Simple"
class.
Package structure is as follows:
Simple.java
public c l a s s Simple {
public s t a t i c i n t add ( i n t a , i n t b ) {
r e t u r n a+b ;
}
}
13
14
Last, but not the least, the library should be constantly updated and optimized. Documentation is
important. If the library is not documented well, you may totally forget a function you programmed
a year ago. Proper package names should be used to indicate the function of classes and methods.
For example, you can name first layer of the packages by following the package names of standard
Java library: programcreek.util, programcreek.io, programcreek.math, programcreek.text, etc. You
domain specific knowledge then can be used in the next level. In addition, always do enough
research first and make sure there is no implements of what you want to do before you start program
anything. Libraries from industry utilizes the power of thousands of smart developers.
Program Creek
4
W H E N A N D H O W A J AVA C L A S S I S L O A D E D A N D I N I T I A L I Z E D ?
In Java, you first write a .java file which is then compiled to .class file during compile time. Java is
capable of loading classes at run time. The confusion is what is the difference between "load" and
"initialize". When and how is a Java class loaded and initialized? It can be clearly illustrated by
using a simple example below.
4.1
C/C++ is compiled to native machine code first and then it requires a linking step after compilation. What the linking does is combining source files from different places and form an executable
program. Java does not do that. The linking-like step for Java is done when they are loaded into
JVM.
Different JVMs load classes in different ways, but the basic rule is only loading classes when they
are needed. If there are some other classes that are required by the loaded class, they will also be
loaded. The loading process is recursive.
4.2
In Java, loading policies is handled by a ClassLoader. The following example shows how and when
a class is loaded for a simple program.
TestLoader.java
package compiler ;
public c l a s s TestLoader {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
System . out . p r i n t l n ( " t e s t " ) ;
}
}
A.java
package compiler ;
public c l a s s A {
public void method ( ) {
System . out . p r i n t l n ( " i n s i d e o f A" ) ;
15
}
}
By running the following command, we can get information about each class loaded. The "verbose:class" option displays information about each class loaded.
j a v a verbose : c l a s s c l a s s p a t h /home/ron/workspace/ U l t i m a t e T e s t /bin/ compiler .
TestLoader
Part of output:
[ Loaded sun . misc . J a v a S e c u r i t y P r o t e c t i o n D o m a i n A c c e s s from /usr/ l o c a l / j a v a /j d k1
. 6 . 0 _34/ j r e / l i b / r t . j a r ]
[ Loaded j a v a . s e c u r i t y . ProtectionDomain$2 from /usr/ l o c a l / j a v a /j d k1 . 6 . 0 _34/ j r e /
lib/rt . jar ]
[ Loaded j a v a . s e c u r i t y . ProtectionDomain$Key from /usr/ l o c a l / j a v a /j dk 1 . 6 . 0 _34/ j r e /
lib/rt . jar ]
[ Loaded j a v a . s e c u r i t y . P r i n c i p a l from /usr/ l o c a l / j a v a /j dk 1 . 6 . 0 _34/ j r e / l i b / r t . j a r ]
[ Loaded compiler . TestLoader from f i l e : /home/xiwang/workspace/ U l t i m a t e T e s t /bin /]
test
[ Loaded j a v a . lang . Shutdown from /usr/ l o c a l / j a v a /jd k 1 . 6 . 0 _34/ j r e / l i b / r t . j a r ]
[ Loaded j a v a . lang . Shutdown$Lock from /usr/ l o c a l / j a v a /j dk 1 . 6 . 0 _34/ j r e / l i b / r t . j a r ]
And run the same command again, the output would be:
[ Loaded sun . misc . J a v a S e c u r i t y P r o t e c t i o n D o m a i n A c c e s s from /usr/ l o c a l / j a v a /j d k1
. 6 . 0 _34/ j r e / l i b / r t . j a r ]
[ Loaded j a v a . s e c u r i t y . ProtectionDomain$2 from /usr/ l o c a l / j a v a /j d k1 . 6 . 0 _34/ j r e /
lib/rt . jar ]
[ Loaded j a v a . s e c u r i t y . ProtectionDomain$Key from /usr/ l o c a l / j a v a /j dk 1 . 6 . 0 _34/ j r e /
lib/rt . jar ]
[ Loaded j a v a . s e c u r i t y . P r i n c i p a l from /usr/ l o c a l / j a v a /j dk 1 . 6 . 0 _34/ j r e / l i b / r t . j a r ]
[ Loaded compiler . TestLoader from f i l e : /home/xiwang/workspace/ U l t i m a t e T e s t /bin /]
test
Program Creek
16
We can see the difference highlighted in red. A.class is loaded only when it is used. In summary, a
class is loaded:
when the new bytecode is executed. For example, SomeClass f = new SomeClass();
when the bytecodes make a static reference to a class. For example, System.out.
4.3
A class is initialized when a symbol in the class is first used. When a class is loaded it is not
initialized.
JVM will initialize superclass and fields in textual order, initialize static, final fields first, and give
every field a default value before initialization.
Java Class Instance Initialization is an example that shows the order of execution for field, static
field and constructor.
Program Creek
17
5
H O W S TAT I C T Y P E C H E C K I N G W O R K S I N J AVA ?
From Wiki:
Static type-checking is the process of verifying the type safety of a program based on analysis of a
programs source code.
Dynamic type-checking is the process of verifying the type safety of a program at runtime
Java uses static type checking to analyze the program during compile-time to prove the absence
of type errors. The basic idea is never let bad things happen at runtime. By understanding the
following example, you should have a good understanding of how static type checking works in
Java.
5.1
code example
18
5.2
The following line will be illegal, even though the object is being invoked on is a B object. The
problem is that its reference type is A. Compiler doesnt know its real type during compile-time, so
it sees the object as type A.
// illegal
new B ( ) . me ( ) . doB ( ) ;
then the following statement is legal and can pass static type checking:
// legal
( ( C) new B ( ) . me ( ) ) . beBad ( ) ;
Compiler does not know its real time, but runtime will throw a cast exception since B can not be
casted to C:
j a v a . lang . C l a s s C a s t E x c e p t i o n : B cannot be c a s t t o C
Program Creek
19
6
J AVA D O U B L E E X A M P L E
Have you ever met the situation that you get an integer but you really want a double.
For the following method, devide(2,3) will return 0.0.
public s t a t i c double devide ( i n t x , i n t y ) {
r e t u r n x/y ;
}
The problem is that x/y does int division. If you want it to do double division, you can cast one of
the operand. Both (double)x/y and x/(double)y will work.
public s t a t i c double devide ( i n t x , i n t y ) {
r e t u r n ( double ) x/y ;
}
Very often you want to round a double. There are multiple ways to do it, the following is a commonly used and simple method. If you want to round the result to 2 digits, you can use the
following code:
public s t a t i c double devide ( i n t x , i n t y ) {
double z= ( double ) x/y ;
double pro = Math . round ( z 1 0 0 ) ;
r e t u r n pro / 1 0 0 ;
}
20
7
D I A G R A M T O S H O W J AVA S T R I N G S I M M U TA B I L I T Y
7.1
declare a string
s stores the reference of the string object. The arrow below should be interpreted as "store reference
of".
7.2
S t r i n g s2 = s ;
s2 stores the same reference value, since it is the same string object.
21
7.3
concat string
7.4
summary
Once a string is created in memory(heap), it can not be changed. We should note that all methods
of String do not change the string itself, but rather return a new String.
If we need a string that can be modified, we will need StringBuffer or StringBuilder. Otherwise,
there would be a lot of time wasted for Garbage Collection, since each time a new String is created.
Here is an example of StringBuilder usage.
Program Creek
22
8
THE SUBSTRING() METHOD IN JDK 6 AND JDK 7
The substring(int beginIndex, int endIndex) method in JDK 6 and JDK 7 are different. Knowing
the difference can help you better use them. For simplicity reasons, in the following substring()
represent the substring(int beginIndex, int endIndex) method.
8.1
The substring(int beginIndex, int endIndex) method returns a string that starts with beginIndex and
ends with endIndex-1.
S t r i n g x = " abcdef " ;
x = x . substring (1 ,3) ;
System . out . p r i n t l n ( x ) ;
Output:
bc
8.2
You may know that because x is immutable, when x is assigned with the result of x.substring(1,3),
it points to a totally new string like the following:
23
However, this diagram is not exactly right or it represents what really happens in the heap. What
really happens when substring() is called is different between JDK 6 and JDK 7.
8.3
substring() in jdk 6
String is supported by a char array. In JDK 6, the String class contains 3 fields: char value[], int
offset, int count. They are used to store real character array, the first index of the array, the number
of characters in the String.
When the substring() method is called, it creates a new string, but the strings value still points
to the same array in the heap. The difference between the two Strings is their count and offset
values.
Program Creek
24
The following code is simplified and only contains the key point for explain this problem.
/ / JDK 6
S t r i n g ( i n t o f f s e t , i n t count , char value [ ] ) {
t h i s . value = value ;
this . offset = offset ;
t h i s . count = count ;
}
public S t r i n g s u b s t r i n g ( i n t beginIndex , i n t endIndex ) {
/ / c h e c k boundary
r e t u r n new S t r i n g ( o f f s e t + beginIndex , endIndex beginIndex , value ) ;
}
8.4
If you have a VERY long string, but you only need a small part each time by using substring(). This
will cause a performance problem, since you need only a small part, you keep the whole thing. For
JDK 6, the solution is using the following, which will make it point to a real sub string:
x = x . substring (x , y) + " "
8.5
substring() in jdk 7
This is improved in JDK 7. In JDK 7, the substring() method actually create a new array in the
heap.
Program Creek
25
/ / JDK 7
public S t r i n g ( char value [ ] , i n t o f f s e t , i n t count ) {
/ / c h e c k boundary
t h i s . value = Arrays . copyOfRange ( value , o f f s e t , o f f s e t + count ) ;
}
public S t r i n g s u b s t r i n g ( i n t beginIndex , i n t endIndex ) {
/ / c h e c k boundary
i n t subLen = endIndex beginIndex ;
r e t u r n new S t r i n g ( value , beginIndex , subLen ) ;
}
Program Creek
26
9
W H Y S T R I N G I S I M M U TA B L E I N J AVA ?
This is an old yet still popular question. There are multiple reasons that String is designed to be
immutable in Java. A good answer depends on good understanding of memory, synchronization,
data structures, etc. In the following, I will summarize some answers.
9.1
String pool (String intern pool) is a special storage area in Method Area. When a string is created
and if the string already exists in the pool, the reference of the existing string will be returned,
instead of creating a new object and returning its reference.
The following code will create only one string object in the heap.
S t r i n g s t r i n g 1 = " abcd " ;
S t r i n g s t r i n g 2 = " abcd " ;
If string is not immutable, changing the string with one reference will lead to the wrong value for
the other references.
27
9.2
The hashcode of string is frequently used in Java. For example, in a HashMap. Being immutable
guarantees that hashcode will always the same, so that it can be cashed without worrying the
changes.That means, there is no need to calculate hashcode every time it is used. This is more
efficient.
In String class, it has the following code:
p r i v a t e i n t hash ; / / t h i s i s u s e d t o c a c h e h a s h c o d e .
9.3
security
String is widely used as parameter for many java classes, e.g. network connection, opening files,
etc. Were String not immutable, a connection or file would be changed and lead to serious security
threat. The method thought it was connecting to one machine, but was not. Mutable strings could
cause security problem in Reflection too, as the parameters are strings.
Here is a code example:
boolean c on n ec t ( s t r i n g s ) {
if ( ! isSecure ( s ) ) {
throw new S e c u r i t y E x c e p t i o n ( ) ;
}
/ / h e r e w i l l c a u s e p r o b l e m , i f s i s c h a n g e d b e f o r e t h i s by u s i n g o t h e r
references .
causeProblem ( s ) ;
}
In summary, the reasons include design, efficiency, and security. Actually, this is also true for many
other why questions in a Java interview.
Program Creek
28
10
C R E AT E J AVA S T R I N G U S I N G O R C O N S T R U C T O R ?
What is the difference between using double quotes and using constructor?
10.1
a==b is true because a and b are referring to the same string literal in the method area. The memory
references are the same.
When the same string literal is created more than once, only one copy of each distinct string value is
stored. This is called "string interning". All compile-time constant strings in Java are automatically
interned.
Example 2:
S t r i n g c = new S t r i n g ( " abcd " ) ;
S t r i n g d = new S t r i n g ( " abcd " ) ;
System . out . p r i n t l n ( c == d ) ;
// False
System . out . p r i n t l n ( c . e q u a l s ( d ) ) ; / / True
c==d is false because c and d refer to two different objects in the heap. Different objects always have
different memory references.
29
10.2
10.3
Because the literal "abcd" is already of type String, using constructor will create an extra unnecessary
object. Therefore, double quotes should be used if you just need to create a String.
If you do need to create a new object in the heap, constructor should be used. Here is a use
case.
Program Creek
30
11
S T R I N G I S PA S S E D B Y R E F E R E N C E I N J AVA
This is a classic question of Java. Many similar questions have been asked on stackoverflow, and
there are a lot of incorrect/incomplete answers. The question is simple if you dont think too much.
But it could be very confusing, if you give more thought to it.
11.1
It prints "ab".
In C++, the code is as follows:
void change ( s t r i n g &x ) {
x = " cd " ;
}
i n t main ( ) {
s t r i n g x = " ab " ;
change ( x ) ;
cout << x << endl ;
}
it prints "cd".
11.2
x stores the reference which points to the "ab" string in the heap. So when x is passed as a parameter
to the change() method, it still points to the "ab" in the heap like the following:
31
Because java is pass-by-value, the value of x is the reference to "ab". When the method change() gets
invoked, it creates a new "cd" object, and x now is pointing to "cd" like the following:
It seems to be a pretty reasonable explanation. They are clear that Java is always pass-by-value. But
what is wrong here?
11.3
The explanation above has several mistakes. To understand this easily, it is a good idea to briefly
walk though the whole process.
When the string "ab" is created, Java allocates the amount of memory required to store the string
object. Then, the object is assigned to variable x, the variable is actually assigned a reference to the
object. This reference is the address of the memory location where the object is stored.
The variable x contains a reference to the string object. x is not a reference itself! It is a variable that
stores a reference(memory address).
Program Creek
32
Java is pass-by-value ONLY. When x is passed to the change() method, a copy of value of x (a
reference) is passed. The method change() creates another object "cd" and it has a different reference.
It is the variable x that changes its reference(to "cd"), not the reference itself.
11.4
The problem raised from the first code fragment is nothing related with string immutability. Even
if String is replaced with StringBuilder, the result is still the same. The key point is that variable
stores the reference, but is not the reference itself!
11.5
If we really need to change the value of the object. First of all, the object should be changeable, e.g.,
StringBuilder. Secondly, we need to make sure that there is no new object created and assigned to
the parameter variable, because Java is passing-by-value only.
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S t r i n g B u i l d e r x = new S t r i n g B u i l d e r ( " ab " ) ;
change ( x ) ;
System . out . p r i n t l n ( x ) ;
}
public s t a t i c void change ( S t r i n g B u i l d e r x ) {
x . d e l e t e ( 0 , 2 ) . append ( " cd " ) ;
}
Program Creek
33
12
S TA R T F R O M L E N G T H & L E N G T H ( ) I N J AVA
The question is why array has the length field but string does not? Or why string has the length()
method while array does not?
12.1
First of all, an array is a container object that holds a fixed number of values of a single type. After
an array is created, its length never changes[1]. The arrays length is available as a final instance
variable length. Therefore, length can be considered as a defining attribute of an array.
An array can be created by two methods: 1) an array creation expression and 2) an array initializer.
When it is created, the size is specified.
An array creation expression is used in the example above. It specifies the element type, the number
of levels of nested arrays, and the length of the array for at least one of the levels of nesting.
This declaration is also legal, since it specifies one of the levels of nesting.
i n t [ ] [ ] a r r = new i n t [ 3 ] [ ] ;
An array initializer creates an array and provides initial values for all its components. It is written
as a comma-separated list of expressions, enclosed by braces and .
For example,
34
12.2. Q2. WHY THERE IS NOT A CLASS "ARRAY" DEFINED SIMILARLY LIKE "STRING"?
int [ ] arr = { 1 , 2 , 3 } ;
12.2
q2. why there is not a class "array" defined similarly like "string"?
An array contains all the members inherited from class Object(except clone). Why there is not a
class definition of an array? We can not find an Array.java file. A rough explanation is that theyre
hidden from us. You can think about the question - if there IS a class Array, what would it look like?
It would still need an array to hold the array data, right? Therefore, it is not a good idea to define
such a class.
Actually we can get the class of an array by using the following code:
i n t [ ] a r r = new i n t [ 3 ] ;
System . out . p r i n t l n ( a r r . g e t C l a s s ( ) ) ;
Output:
class [ I
"class [I" stands for the run-time type signature for the class object "array with component type
int".
12.3
The backup data structure of a String is a char array. There is no need to define a field that is not
necessary for every application. Unlike C, an Array of characters is not a String in Java.
Program Creek
35
13
H O W T O C H E C K I F A N A R R AY C O N TA I N S A VA L U E I N J AVA
E F F I C I E N T LY ?
How to check if an array (unsorted) contains a certain value? This is a very useful and frequently
used operation in Java. It is also a top voted question on Stack Overflow. As shown in top voted
answers, checking if an array contains a certain value can be done in several different ways, but
the time complexity could be very different. In the following I will show the time each method
takes.
13.1
1) Using List:
public s t a t i c boolean u s e L i s t ( S t r i n g [ ] a r r , S t r i n g t a r g e t V a l u e ) {
r e t u r n Arrays . a s L i s t ( a r r ) . c o n t a i n s ( t a r g e t V a l u e ) ;
}
2) Using Set:
public s t a t i c boolean u s e S e t ( S t r i n g [ ] a r r , S t r i n g t a r g e t V a l u e ) {
Set < S t r i n g > s e t = new HashSet < S t r i n g >( Arrays . a s L i s t ( a r r ) ) ;
return s e t . contains ( targetValue ) ;
}
4) Using Arrays.binarySearech(): * The code below is wrong, it is listed here for completeness.
binarySearch() can ONLY be used on sorted arrays. You will the result is weird below.
public s t a t i c boolean us eAr ra ysB ina ry Sea rch ( S t r i n g [ ] a r r , S t r i n g t a r g e t V a l u e ) {
i n t a = Arrays . b i n a r y S e a r c h ( a r r , t a r g e t V a l u e ) ;
if ( a > 0)
return true ;
36
else
return false ;
}
13.2
time complexity
The approximate time complexity can be compared by using the following code. It is not precise,
just search an array of size 5, 1k, 10k, but the idea is clear.
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S t r i n g [ ] a r r = new S t r i n g [ ] { "CD" ,
/ / use l i s t
long s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 0 0 ; i ++) {
u s e L i s t ( a r r , "A" ) ;
}
long endTime = System . nanoTime ( ) ;
long d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " u s e L i s t : " + d u r a t i o n / 1 0 0 0 0 0 0 ) ;
/ / use s e t
s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 0 0 ; i ++) {
u s e S e t ( a r r , "A" ) ;
}
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " u s e S e t : " + d u r a t i o n / 1 0 0 0 0 0 0 ) ;
/ / use loop
s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 0 0 ; i ++) {
useLoop ( a r r , "A" ) ;
}
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " useLoop : " + d u r a t i o n / 1 0 0 0 0 0 0 ) ;
/ / use Arrays . b i n a r y S e a r c h ( )
s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 0 0 ; i ++) {
us eAr ra ysB ina ry Sea rch ( a r r , "A" ) ;
}
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " useArrayBinary : " + d u r a t i o n / 1 0 0 0 0 0 0 ) ;
}
Result:
Program Creek
37
u s e L i s t : 13
u s e S e t : 72
useLoop : 5
us eAr ra ysB ina ry Sea rch :
Result:
u s e L i s t : 112
u s e S e t : 2055
useLoop : 99
useArrayBinary :
12
Result:
u s e L i s t : 1590
u s e S e t : 23819
useLoop : 1526
useArrayBinary :
12
Clearly, using a simple loop method is more efficient than using any collection. A lot of developers
use the first method, but it is inefficient. Pushing the array to another Collection type will require
spin through all elements to read them in before doing anything with the collection type.
The array must be sorted, if Arrays.binarySearch() method is used. In this case, the array is not
sorted, therefore, it should not be used.
Actually, if you really need to check if a value is contained in some array/collection efficiently, a
sorted list or tree can do it in O(log(n)) or hashset can do it in O(1).
Program Creek
38
14
W H AT E X A C T LY I S N U L L I N J AVA ?
14.1
Recall what is a variable and what is a value. A common metaphor is that a variable is similar to
a box. Just as you can use a box to store something, you can use a variable to store a value. When
declaring a variable, we need to set its type.
There are two major categories of types in Java: primitive and reference. Variables declared of a
primitive type store values; variables declared of a reference type store references. In this case, the
initialization statement declares a variables x. x stores String reference. It is null here.
The following visualization gives a better sense about this concept.
39
14.2
14.3
Now we know what null is. And we know a variable is a storage location and an associated symbolic
name (an identifier) which contains some value. Where exactly x is in memory?
From the diagram of JVM run-time data areas, we know that since each method has a private stack
frame within the threads steak, the local variable are located on that frame.
Program Creek
40
15
C O M PA R A B L E V S C O M PA R AT O R I N J AVA
Comparable and Comparator are two interfaces provided by Java Core API. From their names, you
can tell that they may be used for comparing stuff in some way. But what exactly are they and what
is the difference between them? The following are two examples for answering this question. The
simple examples compare two HDTVs size. How to use Comparable vs. Comparator is obvious
after reading the code.
15.1
comparable
Comparable is implemented by a class in order to be able to comparing object of itself with some
other objects. The class itself must implement the interface in order to be able to compare its
instance(s). The method required for implementation is compareTo(). Here is an example to show
the usage:
c l a s s HDTV implements Comparable<HDTV> {
private int size ;
p r i v a t e S t r i n g brand ;
public HDTV( i n t s i z e , S t r i n g brand ) {
this . size = size ;
t h i s . brand = brand ;
}
public i n t g e t S i z e ( ) {
return siz e ;
}
public void s e t S i z e ( i n t s i z e ) {
this . size = size ;
}
public S t r i n g getBrand ( ) {
r e t u r n brand ;
}
public void setBrand ( S t r i n g brand ) {
t h i s . brand = brand ;
}
41
15.2. COMPARATOR
@Override
public i n t compareTo (HDTV t v ) {
i f ( t h i s . getSize ( ) > tv . getSize ( ) )
return 1 ;
else i f ( t h i s . getSize ( ) < tv . getSize ( ) )
r e t u r n 1;
else
return 0 ;
}
}
public c l a s s Main {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
HDTV t v 1 = new HDTV( 5 5 , " Samsung " ) ;
HDTV t v 2 = new HDTV( 6 0 , " Sony " ) ;
i f ( t v 1 . compareTo ( t v 2 ) > 0 ) {
System . out . p r i n t l n ( t v 1 . getBrand ( ) + " i s b e t t e r . " ) ;
} else {
System . out . p r i n t l n ( t v 2 . getBrand ( ) + " i s b e t t e r . " ) ;
}
}
}
Sony i s b e t t e r .
15.2
comparator
Comparator is capable if comparing objects based on different attributes. e.g. 2 men can be compared based on name or age etc. (this can not be done using comparable. )
The method required to implement is compare(). Now lets use another way to compare those TV
by size. The common use of Comparator is sorting. Both Collections and Arrays classes provide a
sort method which use a Comparator.
import j a v a . u t i l . A r r a y L i s t ;
import j a v a . u t i l . C o l l e c t i o n s ;
import j a v a . u t i l . Comparator ;
c l a s s HDTV {
private int size ;
p r i v a t e S t r i n g brand ;
public HDTV( i n t s i z e , S t r i n g brand ) {
this . size = size ;
t h i s . brand = brand ;
}
public i n t g e t S i z e ( ) {
Program Creek
42
15.2. COMPARATOR
return siz e ;
}
public void s e t S i z e ( i n t s i z e ) {
this . size = size ;
}
public S t r i n g getBrand ( ) {
r e t u r n brand ;
}
public void setBrand ( S t r i n g brand ) {
t h i s . brand = brand ;
}
}
c l a s s SizeComparator implements Comparator<HDTV> {
@Override
public i n t compare (HDTV tv1 , HDTV t v 2 ) {
int tv1Size = tv1 . getSize ( ) ;
int tv2Size = tv2 . getSize ( ) ;
if ( tv1Size > tv2Size ) {
return 1 ;
} else if ( tv1Size < tv2Size ) {
r e t u r n 1;
} else {
return 0 ;
}
}
}
public c l a s s Main {
public s t a t i c void
HDTV t v 1 =
HDTV t v 2 =
HDTV t v 3 =
main ( S t r i n g [ ] a r g s ) {
new HDTV( 5 5 , " Samsung " ) ;
new HDTV( 6 0 , " Sony " ) ;
new HDTV( 4 2 , " Panasonic " ) ;
Output:
Panasonic
Program Creek
43
Samsung
Sony
Often we may use Collections.reverseOrder() method to get a descending order Comparator. Like
the following:
A r r a y L i s t < I n t e g e r > a l = new A r r a y L i s t < I n t e g e r > ( ) ;
a l . add ( 3 ) ;
a l . add ( 1 ) ;
a l . add ( 2 ) ;
System . out . p r i n t l n ( a l ) ;
Collections . sort ( al ) ;
System . out . p r i n t l n ( a l ) ;
Comparator< I n t e g e r > comparator = C o l l e c t i o n s . r e v e r s e O r d e r ( ) ;
C o l l e c t i o n s . s o r t ( a l , comparator ) ;
System . out . p r i n t l n ( a l ) ;
Output:
[3 ,1 ,2]
[1 ,2 ,3]
[3 ,2 ,1]
15.3
In brief, a class that implements Comparable will be comparable, which means it instances can be
compared with each other.
A class that implements Comparator will be a Comparator for some other class. It 1) can be passed
to a sort method, such as Collections.sort() or Arrays.sort(), to allow precise control over the sort
order and 2) can also be used to control the order of certain data structures, such as sorted sets or
sorted maps.
For example, to create a TreeSet. We can either pass the constructor a Comparator or make the
object class comparable.
Approach 1 - TreeSet(Comparator comparator)
c l a s s Dog {
int size ;
Dog ( i n t s ) {
size = s ;
}
}
c l a s s SizeComparator implements Comparator<Dog> {
@Override
public i n t compare ( Dog d1 , Dog d2 ) {
r e t u r n d1 . s i z e d2 . s i z e ;
}
Program Creek
44
}
public c l a s s ImpComparable {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
T r e e S e t <Dog> d = new T r e e S e t <Dog>(new SizeComparator ( ) ) ; / / p a s s
comparator
d . add (new Dog ( 1 ) ) ;
d . add (new Dog ( 2 ) ) ;
d . add (new Dog ( 1 ) ) ;
}
}
Program Creek
45
16
J AVA E Q U A L S ( ) A N D H A S H C O D E ( ) C O N T R A C T
The Java super class java.lang.Object has two very important methods defined:
public boolean e q u a l s ( O b j e c t o b j )
public i n t hashCode ( )
They have been proved to be extremely important to understand, especially when user-defined
objects are added to Maps. However, even advanced-level developers sometimes cant figure out
how they should be used properly. In this post, I will first show an example of a common mistake,
and then explain how equals() and hashCode contract works.
16.1
a common mistake
46
public Apple ( S t r i n g c o l o r ) {
this . color = color ;
}
public boolean e q u a l s ( O b j e c t o b j ) {
i f ( ! ( o b j i n s t a n c e o f Apple ) )
return false ;
i f ( o b j == t h i s )
return true ;
r e t u r n t h i s . c o l o r . e q u a l s ( ( ( Apple ) o b j ) . c o l o r ) ;
}
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Apple a1 = new Apple ( " green " ) ;
Apple a2 = new Apple ( " red " ) ;
/ / hashMap s t o r e s a p p l e t y p e and i t s q u a n t i t y
HashMap<Apple , I n t e g e r > m = new HashMap<Apple , I n t e g e r > ( ) ;
m. put ( a1 , 1 0 ) ;
m. put ( a2 , 2 0 ) ;
System . out . p r i n t l n (m. g e t (new Apple ( " green " ) ) ) ;
}
}
In this example, a green apple object is stored successfully in a hashMap, but when the map is asked
to retrieve this object, the apple object is not found. The program above prints null. However, we
can be sure that the object is stored in the hashMap by inspecting in the debugger:
16.2
The problem is caused by the un-overridden method "hashCode()". The contract between equals()
and hasCode() is that: 1. If two objects are equal, then they must have the same hash code. 2. If two
objects have the same hashcode, they may or may not be equal.
Program Creek
47
The idea behind a Map is to be able to find an object faster than a linear search. Using hashed keys
to locate objects is a two-step process. Internally the Map stores objects as an array of arrays. The
index for the first array is the hashcode() value of the key. This locates the second array which is
searched linearly by using equals() to determine if the object is found.
The default implementation of hashCode() in Object class returns distinct integers for different
objects. Therefore, in the example above, different objects(even with same type) have different
hashCode.
Hash Code is like a sequence of garages for storage, different stuff can be stored in different garages.
It is more efficient if you organize stuff to different place instead of the same garage. So its a good
practice to equally distribute the hashCode value. (Not the main point here though)
The solution is to add hashCode method to the class. Here I just use the color strings length for
demonstration.
public i n t hashCode ( ) {
return this . color . length ( ) ;
}
Program Creek
48
17
O V E R R I D I N G V S . O V E R L O A D I N G I N J AVA
17.1
definitions
Overriding vs. Overloading are two confusing concepts for Java novice programmers.
Overloading is the situation that two or more methods in the same class have the same name but
different arguments.
Overriding means having two methods with the same arguments, but different implementation.
One of them exists in the Parent class and the another exists in the Child Class.
17.2
17.3
example of overriding
Here is an example of overriding. After reading the code, guess the output.
c l a s s Dog {
public void bark ( ) {
System . out . p r i n t l n ( " woof " ) ;
}
}
c l a s s Hound extends Dog {
public void s n i f f ( ) {
System . out . p r i n t l n ( " s n i f f " ) ;
}
public void bark ( ) {
System . out . p r i n t l n ( " bowl " ) ;
}
}
49
public c l a s s Main {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
new Hound ( ) . bark ( ) ;
( ( Dog ) new Hound ( ) ) . bark ( ) ;
/ / ( ( Dog ) new Hound ( ) ) . s n i f f ( ) ;
}
}
Output?
bowl
bowl
A better example:
c l a s s Animal {
void s t i n k y ( ) {
System . out . p r i n t l n ( " s t i n k y animal ! " ) ;
}
}
c l a s s Dog extends Animal {
public void s t i n k y ( ) {
System . out . p r i n t l n ( " s t i n k y dog ! " ) ;
}
public void bark ( ) {
System . out . p r i n t l n ( "wow wow" ) ;
}
}
c l a s s Cow extends Animal {
public void s t i n k y ( ) {
System . out . p r i n t l n ( " s t i n k y cow ! " ) ;
}
}
public c l a s s T e s t O v e r r i d i n g {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Animal o b j = new Dog ( ) ;
obj . stinky ( ) ;
}
}
When you create object like the above and call a method:
Animal o b j = new Dog ( ) ;
obj . stinky ( ) ;
What compiler does is that it checks the class type of object which is Animal here. After that it
checks whether the stinky() exist in Animal or not. Always remember that objects are created at
run-time. So compiler has no way to know that the Dog class stinky() method is to be called. So at
compile time class type of reference variable is checked to check such a method exist or not.
Program Creek
50
Now at run-time, the JVM knows that though the class type of obj is Animal, at run time it is
referring to the object of Dog. So it calls the stinky() of Dog class. This is called Dynamic Polymorphism.
Program Creek
51
18
W H AT I S I N S TA N C E I N I T I A L I Z E R I N J AVA ?
In this post, an example is first given to illustrate what are instance variable initializer, instance
initializer and static initializer. Then how instance initializer works is explained.
18.1
execution order
Look at the following class, do you know which one gets executed first?
public c l a s s Foo {
// instance variable
S t r i n g s = " abc " ;
initializer
// constructor
public Foo ( ) {
System . out . p r i n t l n ( " c o n s t r u c t o r c a l l e d " ) ;
}
// static initializer
static {
System . out . p r i n t l n ( " s t a t i c i n i t i a l i z e r c a l l e d " ) ;
}
// instance i n i t i a l i z e r
{
System . out . p r i n t l n ( " i n s t a n c e i n i t i a l i z e r c a l l e d " ) ;
}
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
new Foo ( ) ;
new Foo ( ) ;
}
}
Output:
static i n i t i a l i z e r called
instance i n i t i a l i z e r called
constructor called
52
instance i n i t i a l i z e r called
constructor called
18.2
The instance initializer above contains a print statement. To understand how it works, we can think
of it as a variable assignment statement(e.g. b = 0), then this would not difficult to understand.
Instead of
int b = 0
Therefore, instance initializer and instance variable initializer are pretty much the same.
18.3
The use of instance initializers are rare, but still it can be a useful alternative to instance variable
initializers if:
Zt
be expressed with
(1) initializer code must handle exceptions (2) perform calculations that canA
an instance variable initializer.
Of course, such code could be written in constructors. But if a class had multiple constructors, you
would have to repeat the code in each constructor.
With an instance initializer, you can just write the code once, and it will be executed no matter what
constructor is used to create the object. (I guess this is just a concept, and it is not used often.)
Zt
Another case in which instance initializers are useful is anonymous inner classes, which canA
declare any constructors at all. (Will this be a good place to place a logging function?)
Program Creek
53
19
WHY FIELD CANT BE OVERRIDDEN?
This article shows the basic object oriented concept in Java - Field Hiding.
19.1
Lets first take a look at the following example which creates two Sub objects. One is assigned to a
Sub reference, the other is assigned to a Super reference.
package oo ;
c l a s s Super {
S t r i n g s = " Super " ;
}
c l a s s Sub extends Super {
S t r i n g s = " Sub " ;
}
public c l a s s F i e l d O v e r r i d i n g {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Sub c1 = new Sub ( ) ;
System . out . p r i n t l n ( c1 . s ) ;
Super c2 = new Sub ( ) ;
System . out . p r i n t l n ( c2 . s ) ;
}
}
We did create two Sub objects, but why the second one prints out "Super"?
19.2
54
Within a class, a field that has the same name as a field in the superclass hides the superclasss field,
even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its
simple name. Instead, the field must be accessed through super. Generally speaking, we dont recommend
hiding fields as it makes code difficult to read.
From this definition, member variables/class fields cannot be overridden like methods. When subclass defines a field with same name, it just declares a new field. Therefore, they can not be accessed
polymorphically. They can not be overridden, which also means they are hidden and can be access
though some ways.
19.3
1). By using parenting reference type, the hidden parent fields can be access, like the example above.
2). By casting you can access the hidden member in the superclass.
System . out . p r i n t l n ( ( ( Super ) c1 ) . s ) ;
Program Creek
55
20
I N H E R I TA N C E V S . C O M P O S I T I O N I N J AVA
This article illustrates the concepts of inheritance vs. composition in Java. It first shows an example
of inheritance, and then shows how to improve the inheritance design by using composition. How
to choose between them is summarized at the end.
20.1
inheritance
Lets suppose we have an Insect class. This class contains two methods: 1) move() and 2) attack().
class Insect {
private int size ;
private String color ;
public I n s e c t ( i n t s i z e , S t r i n g c o l o r ) {
this . size = size ;
this . color = color ;
}
public i n t g e t S i z e ( ) {
return siz e ;
}
public void s e t S i z e ( i n t s i z e ) {
this . size = size ;
}
public S t r i n g g e t C o l o r ( ) {
return color ;
}
public void s e t C o l o r ( S t r i n g c o l o r ) {
this . color = color ;
}
public void move ( ) {
System . out . p r i n t l n ( "Move" ) ;
}
public void a t t a c k ( ) {
56
20.1. INHERITANCE
move ( ) ; / / a s s u m i n g an i n s e c t n e e d s t o move b e f o r e a t t a c k i n g
System . out . p r i n t l n ( " Attack " ) ;
}
}
Now you want to define a Bee class, which is a type of Insect, but have different implementations
of attack() and move(). This can be done by using an inheritance design like the following:
c l a s s Bee extends I n s e c t {
public Bee ( i n t s i z e , S t r i n g c o l o r ) {
super ( s i z e , c o l o r ) ;
}
public void move ( ) {
System . out . p r i n t l n ( " F ly " ) ;
}
public void a t t a c k ( ) {
move ( ) ;
super . a t t a c k ( ) ;
}
}
public c l a s s InheritanceVSComposition {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
I n s e c t i = new Bee ( 1 , " red " ) ;
i . attack ( ) ;
}
}
Program Creek
57
20.1. INHERITANCE
58
Output:
Fl y
Fl y
Attack
"Fly" was printed twice, which indicates move() is called twice. But it should be called only
ONCE.
The problem is caused by the super.attack() method. The attack() method of Insect invokes move()
method. When the subclass calls super.attack(), it also invokes the overridden move() method.
To fix the problem, we can:
eliminate the subclasss attack() method. This will make the subclass depends on the superclasss implementation of attack(). If the attack() method in the superclass is changed later
(which is out of your control), e.g., the superclasss attack() method use another method to
move, the subclass will need to be changed too. This is bad encapsulation.
rewrite the attack() method like the following: public void attack() move(); System.out.println("Attack");
This would guarantee the correct result, because the subclass is not dependent on the superclass any more. However, the code is the duplicate of the superclass. (Image attack() method
does complex things other than just printing a string) This does not following software engineering rule of reusing.
This inheritance design is bad, because the subclass depends on the implementation details of its
superclass. If the superclass changes, the subclass may break.
Program Creek
20.2. COMPOSITION
20.2
composition
Instead of inheritance, composition can be used in this case. Lets first take a look at the composition
solution.
The attack function is abstracted as an interface.
i n t e r f a c e Attack {
public void move ( ) ;
public void a t t a c k ( ) ;
}
Since the attack function is extracted, Insect does not do anything related with attack any longer.
class Insect {
private int size ;
private String color ;
public I n s e c t ( i n t s i z e , S t r i n g c o l o r ) {
this . size = size ;
this . color = color ;
}
public i n t g e t S i z e ( ) {
return siz e ;
}
public void s e t S i z e ( i n t s i z e ) {
this . size = size ;
}
Program Creek
59
20.2. COMPOSITION
public S t r i n g g e t C o l o r ( ) {
return color ;
}
public void s e t C o l o r ( S t r i n g c o l o r ) {
this . color = color ;
}
}
Program Creek
60
public c l a s s InheritanceVSComposition2 {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Bee a = new Bee ( 1 , " b l a c k " , new AttackImpl ( " f l y " , "move " ) ) ;
a . attack ( ) ;
/ / i f you n e e d a n o t h e r i m p l e m e n t a t i o n o f move ( )
/ / t h e r e i s no n e e d t o c h a n g e I n s e c t , we can q u i c k l y u s e new
method t o a t t a c k
Bee b = new Bee ( 1 , " b l a c k " , new AttackImpl ( " f l y " , " s t i n g " ) ) ;
b . attack ( ) ;
}
}
fly
move
fly
sting
20.3
The following two items can guide the selection between inheritance and composition:
If there is an IS-A relation, and a class wants to expose all the interface to another class,
inheritance is likely to be preferred.
If there is a HAS-A relationship, composition is preferred.
In summary, Inheritance and composition both have their uses, and it pays to understand their
relative merits.
Program Creek
61
21
J AVA E N U M E X A M P L E S
An enum in Java is just like any other class, with a predefined set of instances. Here are several
examples to highlight how to use Java Enum.
21.1
simple example
Output:
RED
YELLOW
BLUE
21.2
with constructor
62
21.3
Recall the definition of Java Enum which is like any other class, with a predefined set of instances.
A good use case is preventing the possibility of an invalid parameter. For example, imagine the
following method:
public void doSomethingWithColor ( i n t c o l o r ) ;
This is ambiguous, and other developers have no idea how value to use. If you have an enum Color
with BLACK, RED, etc. the signature becomes:
public void doSomethingWithColor ( Color c o l o r ) ;
Code calling this method will be far more readable, and cant provide invalid data.
Program Creek
63
22
4 T Y P E S O F J AVA I N N E R C L A S S E S
There are 4 different types of inner classes you can use in Java. The following gives their name and
examples.
22.1
c l a s s Outer {
s t a t i c c l a s s Inner {
void go ( ) {
System . out . p r i n t l n ( " I n n e r c l a s s r e f e r e n c e i s : " + t h i s ) ;
}
}
}
public c l a s s T e s t {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Outer . I n n e r n = new Outer . I n n e r ( ) ;
n . go ( ) ;
}
}
I n n e r c l a s s r e f e r e n c e i s : Outer$Inner@19e7ce87
22.2
Member class is instance-specific. It has access to all methods, fields, and the Outers this reference.
public c l a s s Outer {
private int x = 100;
public void makeInner ( ) {
I n n e r i n = new I n n e r ( ) ;
i n . seeOuter ( ) ;
}
c l a s s Inner {
public void seeOuter ( ) {
System . out . p r i n t l n ( " Outer x i s " + x ) ;
64
22.3
public c l a s s Outer {
private String x = " outer " ;
public void d o S t u f f ( ) {
c l a s s MyInner {
public void seeOuter ( ) {
System . out . p r i n t l n ( " x i s " + x ) ;
}
}
MyInner i = new MyInner ( ) ;
i . seeOuter ( ) ;
}
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Outer o = new Outer ( ) ;
o . doStuff ( ) ;
}
}
x i s outer
public c l a s s Outer {
private s t a t i c String x = " s t a t i c outer " ;
public s t a t i c void d o S t u f f ( ) {
c l a s s MyInner {
public void seeOuter ( ) {
System . out . p r i n t l n ( " x i s " + x ) ;
}
}
MyInner i = new MyInner ( ) ;
Program Creek
65
i . seeOuter ( ) ;
}
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Outer . d o S t u f f ( ) ;
}
}
x i s s t a t i c outer
22.4
This is frequently used when you add an action listener to a widget in a GUI application.
button . a d d A c t i o n L i s t e n e r (new A c t i o n L i s t e n e r ( ) {
public void acti onPerfor med ( ActionEvent e ) {
comp . s e t T e x t ( " Button has been c l i c k e d " ) ;
}
}) ;
Program Creek
66
23
W H AT I S I N N E R I N T E R FA C E I N J AVA ?
23.1
Inner interface is also called nested interface, which means declare an interface inside of another
interface. For example, the Entry interface is declared in the Map interface.
public i n t e r f a c e Map {
i n t e r f a c e Entry {
i n t getKey ( ) ;
}
void c l e a r ( ) ;
}
23.2
23.3
To figure out how inner interface works, we can compare it with nested classes. Nested classes can
be considered as a regular method declared in outer class. Since a method can be declared as static
or non-static, similarly nested classes can be static and non-static. Static class is like a static method,
it can only access outer class members through objects. Non-static class can access any member of
the outer class.
67
Because an interface can not be instantiated, the inner interface only makes sense if it is static.
Therefore, by default inter interface is static, no matter you manually add static or not.
23.4
Map.java
public i n t e r f a c e Map {
i n t e r f a c e Entry {
i n t getKey ( ) ;
}
Program Creek
68
void c l e a r ( ) ;
}
MapImpl.java
public c l a s s MapImpl implements Map {
Program Creek
69
24
C O N S T R U C T O R S O F S U B A N D S U P E R C L A S S E S I N J AVA ?
24.1
why creating an object of the sub class invokes also the constructor of
the super class?
c l a s s Super {
String s ;
public Super ( ) {
System . out . p r i n t l n ( " Super " ) ;
}
}
public c l a s s Sub extends Super {
public Sub ( ) {
System . out . p r i n t l n ( " Sub " ) ;
}
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Sub s = new Sub ( ) ;
}
}
It prints:
Super
Sub
When inheriting from another class, super() has to be called first in the constructor. If not, the
compiler will insert that call. This is why super constructor is also invoked when a Sub object is
created.
This doesnt create two objects, only one Sub object. The reason to have super constructor called is
that if super class could have private fields which need to be initialized by its constructor.
After compiler inserts the super constructor, the sub class constructor looks like the following:
70
24.2. A COMMON ERROR MESSAGE: IMPLICIT SUPER CONSTRUCTOR IS UNDEFINED FOR DEFAULT CONSTRUCT
public Sub ( ) {
super ( ) ;
System . out . p r i n t l n ( " Sub " ) ;
}
24.2
a common error message: implicit super constructor is undefined for default constructor
This compilation error occurs because the default super constructor is undefined. In Java, if a class
does not define a constructor, compiler will insert a default argument-less constructor for the class
by default. If a constructor is defined in Super class, in this case Super(String s), compiler will not
insert the default argument-less constructor. This is the situation for the Super class above.
The constructors of the Sub class, either with-argument or argument-less, will call the argument-less
Super constructor. Since compiler tries to insert super() to the 2 constructors in the Sub class, but
the Supers default constructor is not defined, compiler reports the error message.
To fix this problem, simply 1) add a Super() constructor to the Super class like
public Super ( ) {
System . out . p r i n t l n ( " Super " ) ;
}
Program Creek
24.3
The Sub constructor explicitly call the super constructor with parameter. The super constructor is
defined, and good to invoke.
24.4
the rule
In brief, the rules is: sub class constructor has to invoke super class instructor, either explicitly by
programmer or implicitly by compiler. For either way, the invoked super constructor has to be
defined.
24.5
Why Java doesnt provide default constructor, if class has a constructor with parameter(s)?
Some answers: http://stackoverflow.com/q/16046200/127859
Program Creek
72
25
J AVA A C C E S S L E V E L F O R M E M B E R S : P U B L I C , P R O T E C T E D , P R I VAT E
Java access level contains two parts: 1) access level for classes and 2) access level for members.
For class access level, the keyword can be public or no explicit modifier(package-private). For
member access level, the keyword can be public, protected, package-private (no explicit modifier),
or private.
The following table summarizes the access level of different modifiers for members. Access level
determines the accessibility of fields and methods. It has 4 levels: public, protected, package-private
(no explicit modifier), or private.
73
26
W H E N T O U S E P R I VAT E C O N S T R U C T O R S I N J AVA ?
If a method is private, it means that it can not be accessed from any class other than itself. This
is the access control mechanism provided by Java. When it is used appropriately, it can produce
security and functionality. Constructors, like regular methods, can also be declared as private. You
may wonder why we need a private constructor since it is only accessible from its own class. When
a class needs to prevent the caller from creating objects. Private constructors are suitable. Objects
can be constructed only internally.
One application is in the singleton design pattern. The policy is that only one object of that class is
supposed to exist. So no other class than itself can access the constructor. This ensures the single
instance existence of the class. Private constructors have been widely used in JDK, the following
code is part of Runtime class.
public c l a s s Runtime {
p r i v a t e s t a t i c Runtime currentRuntime = new Runtime ( ) ;
public s t a t i c Runtime getRuntime ( ) {
r e t u r n currentRuntime ;
}
/ / Don t l e t a n y o n e e l s e i n s t a n t i a t e t h i s c l a s s
p r i v a t e Runtime ( ) {
}
}
74
27
2 E X A M P L E S T O S H O W H O W J AVA E X C E P T I O N H A N D L I N G W O R K S
There are 2 examples below. One shows all caller methods also need to handle exceptions thrown
by the callee method. The other one shows the super class can be used to catch or handle subclass
exceptions.
27.1
Here is a program which handles exceptions. Just test that, if an exception is thrown in one method,
not only that method, but also all methods which call that method have to declare or throw that
exception.
public c l a s s e x c e p t i o n T e s t {
private s t a t i c Exception exception ;
public s t a t i c void main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n {
callDoOne ( ) ;
}
public s t a t i c void doOne ( ) throws E x c e p t i o n {
throw e x c e p t i o n ;
}
public s t a t i c void callDoOne ( ) throws E x c e p t i o n {
doOne ( ) ;
}
}
27.2
The following is also OK, because the super class can be used to catch or handle subclass exceptions:
c l a s s myException extends E x c e p ti o n {
}
public c l a s s e x c e p t i o n T e s t {
75
27.2. THE SUPER CLASS CAN BE USED TO CATCH OR HANDLE SUBCLASS EXCEPTIONS
This is the reason that only one parent class in the catch clause is syntactically safe.
Program Creek
76
28
DIAGRAM OF EXCEPTION HIERARCHY
In Java, exception can be checked or unchecked. They both fit into a class hierarchy. The following
diagram shows Java Exception classes hierarchy.
Red colored are checked exceptions. Any checked exceptions that may be thrown in a method must
either be caught or declared in the methods throws clause. Checked exceptions must be caught at
compile time. Checked exceptions are so called because both the Java compiler and the Java virtual
machine check to make sure this rule is obeyed. Green colored are uncheck exceptions. They are
exceptions that are not expected to be recovered, such as null pointer, divide by 0, etc.
77
78
Program Creek
79
Program Creek
29
S H O W M A N Y WAY S ?
J AVA R E A D A F I L E L I N E B Y L I N E A
The number of total classes of Java I/O is large, and it is easy to get confused when to use which.
The following are two methods for reading a file line by line.
Method 1:
p r i v a t e s t a t i c void r e a d F i l e 1 ( F i l e f i n ) throws IOException {
F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( f i n ) ;
/ / C on st r uc t B u f f e r e d R e a d e r from InputStreamReader
BufferedReader br = new BufferedReader (new InputStreamReader ( f i s ) ) ;
Stri ng l i n e = null ;
while ( ( l i n e = br . readLine ( ) ) ! = n u l l ) {
System . out . p r i n t l n ( l i n e ) ;
}
br . c l o s e ( ) ;
}
Method 2:
p r i v a t e s t a t i c void r e a d F i l e 2 ( F i l e f i n ) throws IOException {
/ / C on st r uc t B u f f e r e d R e a d e r from F i l e R e a d e r
BufferedReader br = new BufferedReader (new F i l e R e a d e r ( f i n ) ) ;
Stri ng l i n e = null ;
while ( ( l i n e = br . readLine ( ) ) ! = n u l l ) {
System . out . p r i n t l n ( l i n e ) ;
}
br . c l o s e ( ) ;
}
80
81
Reading the class hierarchy diagram is also very helpful for understanding those inputstream and
reader related concept: http://www.programcreek.com/2012/05/java-io-class-hierarchy-diagram/.
Program Creek
30
H O W T O W R I T E A F I L E L I N E B Y L I N E I N J AVA ?
This is Java code for writing something to a file. Every time after it runs, a new file is created, and
the previous one is gone. This is different from appending content to a file.
public s t a t i c void w r i t e F i l e 1 ( ) throws IOException {
F i l e f o u t = new F i l e ( " out . t x t " ) ;
FileOutputStream f o s = new FileOutputStream ( f o u t ) ;
B u f f e r e d W r i t e r bw = new B u f f e r e d W r i t e r (new OutputStreamWriter ( f o s ) ) ;
f o r ( i n t i = 0 ; i < 1 0 ; i ++) {
bw . w r i t e ( " something " ) ;
bw . newLine ( ) ;
}
bw . c l o s e ( ) ;
}
This example use FileOutputStream, instead you can use FileWriter or PrintWriter which is normally
good enough for a text file operations.
Use FileWriter:
public s t a t i c void w r i t e F i l e 2 ( ) throws IOException {
F i l e W r i t e r fw = new F i l e W r i t e r ( " out . t x t " ) ;
f o r ( i n t i = 0 ; i < 1 0 ; i ++) {
fw . w r i t e ( " something " ) ;
}
fw . c l o s e ( ) ;
}
Use PrintWriter:
public s t a t i c void w r i t e F i l e 3 ( ) throws IOException {
P r i n t W r i t e r pw = new P r i n t W r i t e r (new F i l e W r i t e r ( " out . t x t " ) ) ;
f o r ( i n t i = 0 ; i < 1 0 ; i ++) {
pw. w r i t e ( " something " ) ;
}
82
83
pw. c l o s e ( ) ;
}
Use OutputStreamWriter:
public s t a t i c void w r i t e F i l e 4 ( ) throws IOException {
F i l e f o u t = new F i l e ( " out . t x t " ) ;
FileOutputStream f o s = new FileOutputStream ( f o u t ) ;
OutputStreamWriter osw = new OutputStreamWriter ( f o s ) ;
f o r ( i n t i = 0 ; i < 1 0 ; i ++) {
osw . w r i t e ( " something " ) ;
}
osw . c l o s e ( ) ;
}
Program Creek
31
FILEOUTPUTSTREAM VS. FILEWRITER
When we use Java to write something to a file, we can do it in the following two ways. One uses
FileOutputStream, the other uses FileWriter.
Using FileOutputStream:
F i l e f o u t = new F i l e ( f i l e _ l o c a t i o n _ s t r i n g ) ;
FileOutputStream f o s = new FileOutputStream ( f o u t ) ;
B u f f e r e d W r i t e r out = new B u f f e r e d W r i t e r (new OutputStreamWriter ( f o s ) ) ;
out . w r i t e ( " something " ) ;
Using FileWriter:
F i l e W r i t e r f s t r e a m = new F i l e W r i t e r ( f i l e _ l o c a t i o n _ s t r i n g ) ;
B u f f e r e d W r i t e r out = new B u f f e r e d W r i t e r ( f s t r e a m ) ;
out . w r i t e ( " something " ) ;
Both will work, but what is the difference between FileOutputStream and FileWriter?
There are a lot of discussion on each of those classes, they both are good implements of file i/o
concept that can be found in a general operating systems. However, we dont care how it is designed,
but only how to pick one of them and why pick it that way.
From Java API Specification:
FileOutputStream is meant for writing streams of raw bytes such as image data. For writing streams of
characters, consider using FileWriter.
If you are familiar with design patterns, FileWriter is a typical usage of Decorator pattern actually. I
have use a simple tutorial to demonstrate the Decorator pattern, since it is very important and very
useful for many designs.
One application of FileOutputStream is converting a file to a byte array.
84
32
S H O U L D . C L O S E ( ) B E P U T I N F I N A L LY B L O C K O R N O T ?
The following are 3 different ways to close a output writer. The first one puts close() method in
try clause, the second one puts close in finally clause, and the third one uses a try-with-resources
statement. Which one is the right or the best?
/ / c l o s e ( ) i s in try c l a u s e
try {
P r i n t W r i t e r out = new P r i n t W r i t e r (
new B u f f e r e d W r i t e r (
new F i l e W r i t e r ( " out . t x t " , t r u e ) ) ) ;
out . p r i n t l n ( " t h e t e x t " ) ;
out . c l o s e ( ) ;
} c a t c h ( IOException e ) {
e . printStackTrace ( ) ;
}
/ / c l o s e ( ) i s in f i n a l l y c l a u s e
P r i n t W r i t e r out = n u l l ;
try {
out = new P r i n t W r i t e r (
new B u f f e r e d W r i t e r (
new F i l e W r i t e r ( " out . t x t " , t r u e ) ) ) ;
out . p r i n t l n ( " t h e t e x t " ) ;
} c a t c h ( IOException e ) {
e . printStackTrace ( ) ;
} finally {
i f ( out ! = n u l l ) {
out . c l o s e ( ) ;
}
}
/ / t r y with r e s o u r c e s t a t e m e n t
t r y ( P r i n t W r i t e r out2 = new P r i n t W r i t e r (
new B u f f e r e d W r i t e r (
new F i l e W r i t e r ( " out . t x t " , t r u e ) ) ) ) {
out2 . p r i n t l n ( " t h e t e x t " ) ;
} c a t c h ( IOException e ) {
e . printStackTrace ( ) ;
}
85
32.1. ANSWER
32.1
answer
Because the Writer should be closed in either case (exception or no exception), close() should be put
in finally clause.
From Java 7, we can use try-with-resources statement.
Program Creek
86
33
H O W T O U S E J AVA P R O P E R T I E S F I L E ?
For configuration purposes, using properties file is a good way of reusing. In this way, when
the code is packaged to a jar file, other users can just put the different configurations in the config.properties file. The following is a simple example of using properties file.
1. create the file hierarchy like the following. Mainly remember to put the config.properties file under src package. Other testing code and database class are put in different package under src.
87
88
Program Creek
34
S T H E B A S I C I D E A O F J AVA S Y N C H R O N I Z AT I O N
MONITORS A
If you took operating system course in college, you might remember that monitor is an important
concept of synchronization in operating systems. It is also used in Java synchronization. This post
uses an analogy to explain the basic idea of "monitor".
34.1
what is a monitor?
A monitor can be considered as a building which contains a special room. The special room can
be occupied by only one customer(thread) at a time. The room usually contains some data and
code.
If a customer wants to occupy the special room, he has to enter the Hallway(Entry Set) to wait first.
Scheduler will pick one based on some criteria(e.g. FIFO). If he is suspended for some reason, he
will be sent to the wait room, and be scheduled to reenter the special room later. As it is shown in
the diagram above, there are 3 rooms in this building.
89
In brief, a monitor is a facility which monitors the threads access to the special room. It ensures
that only one thread can access the protected data or code.
34.2
In the Java virtual machine, every object and class is logically associated with a monitor. To implement the mutual exclusion capability of monitors, a lock (sometimes called a mutex) is associated
with each object and class. This is called a semaphore in operating systems books, mutex is a binary
semaphore.
If one thread owns a lock on some data, then no others can obtain that lock until the thread that
owns the lock releases it. It would be not convenient if we need to write a semaphore all the time
when we do multi-threading programming. Luckily, we dont need to since JVM does that for us
automatically.
To claim a monitor region which means data not accessible by more than one thread, Java provide
synchronized statements and synchronized methods. Once the code is embedded with synchronized keyword, it is a monitor region. The locks are implemented in the background automatically
by JVM.
34.3
We know that each object/class is associated with a Monitor. I think it is good to say that each object
has a monitor, since each object could have its own critical section, and capable of monitoring the
thread sequence.
Program Creek
90
To enable collaboration of different threads, Java provide wait() and notify() to suspend a thread
and to wake up another thread that are waiting on the object respectively. In addition, there are 3
other versions:
wait ( long timeout , i n t nanos )
wait ( long timeout ) n o t i f i e d by o t h e r t h r e a d s or n o t i f i e d by timeout .
notify ( al l )
Those methods can only be invoked within a synchronized statement or synchronized method.
The reason is that if a method does not require mutual exclusion, there is no need to monitor or
collaborate between threads, every thread can access that method freely.
Here are some synchronization code examples.
Program Creek
91
35
H O W T O M A K E A M E T H O D T H R E A D - S A F E I N J AVA ?
Interview Question:
Is the following method thread-safe? How to make it thread-safe?
c l a s s MyCounter {
private s t a t i c int counter = 0 ;
public s t a t i c i n t getCount ( ) {
r e t u r n c o u n t e r ++;
}
}
This post explains a general interview question that has been asked by Google and a lot of companies. Its low-level and not about how to design concurrent program.
First of all, the answer is NO. The method is not thread-safe, because the counter++ operation is
not atomic, which means it consists more than one atomic operations. In this case, one is accessing
value and the other is increasing the value by one.
When Thread 1 accesses the method at t1, Thread 2 may not be done with the method. So the value
returned to Thread 1 is the value that has not been increased.
92
35.1
Adding synchronized to this method will makes it thread-safe. When synchronized is added to a
static method, the Class object is the object which is locked.
Is marking it synchronized enough? The answer is YES.
c l a s s MyCounter {
private s t a t i c int counter = 0 ;
public s t a t i c synchronized i n t getCount ( ) {
r e t u r n c o u n t e r ++;
}
}
If the method is not static, then adding synchronized keyword willsynchronize the instance of the
class, not the Class object.
35.2
In this particular counter example, we actually can make count++ atomic by using AtomicInteger
from the package "java.util.concurrent.atomic".
import j a v a . u t i l . c o n c u r r e n t . atomic . AtomicInteger ;
public c l a s s MyCounter {
p r i v a t e s t a t i c AtomicInteger c o u n t e r = new AtomicInteger ( 0 ) ;
public s t a t i c i n t getCount ( ) {
r e t u r n c o u n t e r . getAndIncrement ( ) ;
}
}
35.3
Program Creek
93
36
T H E I N T E R FA C E A N D C L A S S H I E R A R C H Y D I A G R A M O F J AVA
COLLECTIONS
36.1
collection vs collections
First of all, "Collection" and "Collections" are two different concepts. As you will see from the
hierarchy diagram below, "Collection" is a root interface in the Collection hierarchy but "Collections"
is a class which provide static methods to manipulate on some Collection types.
36.2
94
36.3
Program Creek
95
36.4
summary of classes
36.5
code example
Program Creek
96
Output:
A r r a y L i s t Elements
[ Program , Creek , Java , J a v a ]
L i n k e d L i s t Elements
[ Program , Creek , Java , J a v a ]
S e t Elements
[ t u t o r i a l , Creek , Program , J a v a ]
Map Elements
{ Windows=XP , Website=programcreek . com , Language=J a v a }
Program Creek
97
37
A SIMPLE TREESET EXAMPLE
The following is a very simple TreeSet example. From this simple example, you will see:
TreeSet is sorted
How to iterate a TreeSet
How to check empty
How to retrieve first/last element
How to remove an element
If you want to know more about Java Collection, check out the Java Collection hierarchy diagram.
import j a v a . u t i l . I t e r a t o r ;
import j a v a . u t i l . T r e e S e t ;
public c l a s s TreeSetExample {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
System . out . p r i n t l n ( " Tree S e t Example ! \ n " ) ;
T r e e S e t < I n t e g e r > t r e e = new T r e e S e t < I n t e g e r > ( ) ;
t r e e . add ( 1 2 ) ;
t r e e . add ( 6 3 ) ;
t r e e . add ( 3 4 ) ;
t r e e . add ( 4 5 ) ;
/ / h e r e i t t e s t i t s s o r t e d , 63 i s t h e l a s t e l e m e n t . s e e o u t p u t b e l o w
I t e r a t o r <Integer > i t e r a t o r = tree . i t e r a t o r ( ) ;
System . out . p r i n t ( " Tree s e t data : " ) ;
/ / Displaying the Tree s e t data
while ( i t e r a t o r . hasNext ( ) ) {
System . out . p r i n t ( i t e r a t o r . n ex t ( ) + " " ) ;
}
System . out . p r i n t l n ( ) ;
/ / Check empty o r n o t
i f ( t r e e . isEmpty ( ) ) {
System . out . p r i n t ( " Tree S e t i s empty . " ) ;
} else {
98
99
Output:
Tree S e t Example !
Tree s e t data : 12 34 45 63
Tree S e t s i z e : 4
F i r s t data : 12
L a s t data : 63
Data i s removed from t r e e s e t
Now t h e t r e e s e t c o n t a i n : 12 34 63
Now t h e s i z e o f t r e e s e t : 3
Tree S e t i s empty .
Program Creek
38
D E E P U N D E R S TA N D I N G O F A R R AY S . S O R T ( )
Arrays.sort(T[], Comparator <? super T >c) is a method for sorting user-defined object array. The
official Java Doc briefly describe what it does, but not much for deep understanding. In this post, I
will walk though the key information for deeper understanding of this method.
38.1
By reading the following example, you can quickly get an idea of how to use this method correctly. A
Comparator is defined for comparing Dogs by size and then the Comparator is used as a parameter
for the sort method.
import j a v a . u t i l . Arrays ;
import j a v a . u t i l . Comparator ;
c l a s s Dog {
int size ;
public Dog ( i n t s ) {
size = s ;
}
}
c l a s s DogSizeComparator implements Comparator<Dog>{
@Override
public i n t compare ( Dog o1 , Dog o2 ) {
r e t u r n o1 . s i z e o2 . s i z e ;
}
}
public c l a s s ArraySort {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Dog d1 = new Dog ( 2 ) ;
Dog d2 = new Dog ( 1 ) ;
Dog d3 = new Dog ( 3 ) ;
Dog [ ] dogArray = { d1 , d2 , d3 } ;
100
printDogs ( dogArray ) ;
Arrays . s o r t ( dogArray , new DogSizeComparator ( ) ) ;
printDogs ( dogArray ) ;
}
public s t a t i c void printDogs ( Dog [ ] dogs ) {
f o r ( Dog d : dogs )
System . out . p r i n t ( d . s i z e + " " ) ;
System . out . p r i n t l n ( ) ;
}
}
Output:
2 1 3
1 2 3
38.2
As this is a perfect example of Strategy pattern, it is worth to mention here why strategy pattern
is good for this situation. In brief, Strategy pattern enables different algorithms get selected at runtime. In this case, by passing different Comparator, different algorithms can get selected. Based
on the example above and now assuming you have another Comparator which compares Dogs by
weight instead of by size, you can simply create a new Comparator like the following.
c l a s s Dog {
int size ;
i n t weight ;
public Dog ( i n t s , i n t w) {
size = s ;
weight = w;
}
}
c l a s s DogSizeComparator implements Comparator<Dog>{
@Override
public i n t compare ( Dog o1 , Dog o2 ) {
r e t u r n o1 . s i z e o2 . s i z e ;
}
}
c l a s s DogWeightComparator implements Comparator<Dog>{
@Override
public i n t compare ( Dog o1 , Dog o2 ) {
r e t u r n o1 . weight o2 . weight ;
}
Program Creek
101
}
public c l a s s ArraySort {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Dog d1 = new Dog ( 2 , 5 0 ) ;
Dog d2 = new Dog ( 1 , 3 0 ) ;
Dog d3 = new Dog ( 3 , 4 0 ) ;
Dog [ ] dogArray = { d1 , d2 , d3 } ;
printDogs ( dogArray ) ;
Arrays . s o r t ( dogArray , new DogSizeComparator ( ) ) ;
printDogs ( dogArray ) ;
Arrays . s o r t ( dogArray , new DogWeightComparator ( ) ) ;
printDogs ( dogArray ) ;
}
public s t a t i c void printDogs ( Dog [ ] dogs ) {
f o r ( Dog d : dogs )
System . out . p r i n t ( " s i z e = " +d . s i z e + " weight= " + d . weight
+ " ");
System . out . p r i n t l n ( ) ;
}
}
s i z e =2 weight =50 s i z e =1 weight =30 s i z e =3 weight =40
s i z e =1 weight =30 s i z e =2 weight =50 s i z e =3 weight =40
s i z e =1 weight =30 s i z e =3 weight =40 s i z e =2 weight =50
Comparator is just an interface. Any Comparator that implements this interface can be used during
run-time. This is the key idea of Strategy design pattern.
38.3
It is straightforward if Comparator <T >c is the parameter, but the second parameter is Comparator<? super T >c. <? super T >means the type can be T or its super types. Why it allows
super types? The answer is: This approach allows using same comparator for all sub classes. This
is almost obvious in the following example.
import j a v a . u t i l . Arrays ;
import j a v a . u t i l . Comparator ;
c l a s s Animal {
int size ;
}
c l a s s Dog extends Animal {
public Dog ( i n t s ) {
Program Creek
102
size = s ;
}
}
c l a s s Cat extends Animal {
public Cat ( i n t s ) {
size = s ;
}
}
c l a s s AnimalSizeComparator implements Comparator<Animal >{
@Override
public i n t compare ( Animal o1 , Animal o2 ) {
r e t u r n o1 . s i z e o2 . s i z e ;
}
/ / i n t h i s way , a l l sub c l a s s e s o f Animal can u s e t h i s c o m p a r a t o r .
}
public c l a s s ArraySort {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Dog d1 = new Dog ( 2 ) ;
Dog d2 = new Dog ( 1 ) ;
Dog d3 = new Dog ( 3 ) ;
Dog [ ] dogArray = { d1 , d2 , d3 } ;
printDogs ( dogArray ) ;
Arrays . s o r t ( dogArray , new AnimalSizeComparator ( ) ) ;
printDogs ( dogArray ) ;
System . out . p r i n t l n ( ) ;
/ / when
Cat c1
Cat c2
Cat c3
Cat [ ] c a t A r r a y = { c1 , c2 , c3 } ;
printDogs ( c a t A r r a y ) ;
Arrays . s o r t ( catArray , new AnimalSizeComparator ( ) ) ;
printDogs ( c a t A r r a y ) ;
}
public s t a t i c void printDogs ( Animal [ ] animals ) {
f o r ( Animal a : animals )
System . out . p r i n t ( " s i z e = " +a . s i z e + " " ) ;
System . out . p r i n t l n ( ) ;
}
}
Program Creek
103
38.4. SUMMARY
s i z e =2 s i z e =1 s i z e =3
s i z e =1 s i z e =2 s i z e =3
s i z e =2 s i z e =1 s i z e =3
s i z e =1 s i z e =2 s i z e =3
38.4
summary
Program Creek
104
39
H O W D E V E L O P E R S S O R T I N J AVA ?
While analyzing source code of a large number of open source Java projects, I found Java developers
frequently sort in two ways. One is using the sort() method of Collections or Arrays, and the other
is using sorted data structures, such as TreeMap and TreeSet.
39.1
39.2
105
}
}) ;
s o r t e d S e t . addAll ( u n s o r t e d S e t ) ;
This approach is very useful, if you would do a lot of search operations for the collection. The sorted
data structure will give time complexity of O(logn), which is lower than O(n).
39.3
bad practices
There are still bad practices, such as using self-defined sorting algorithm. Take the code below for
example, not only the algorithm is not efficient, but also it is not readable. This happens a lot in
different forms of variations.
double t ;
f o r ( i n t i = 0 ; i < 2 ; i ++)
f o r ( i n t j = i + 1 ; j < 3 ; j ++)
if ( r [ j ] < r [ i ]) {
t = r[ i ];
r[ i ] = r[ j ];
r[ j ] = t ;
}
Program Creek
106
40
A R R AY L I S T V S . L I N K E D L I S T V S . V E C T O R
40.1
list overview
List, as its name indicates, is an ordered sequence of elements. When we talk about List, it is a good
idea to compare it with Set which is a set of unique and unordered elements. The following is the
class hierarchy diagram of Collection. From that you can get a general idea of Java Collections.
40.2
From the hierarchy diagram, they all implement List interface. They are very similar to use. Their
main difference is their implementation which causes different performance for different operations.
ArrayList is implemented as a resizable array. As more elements are added to ArrayList, its size
is increased dynamically. Its elements can be accessed directly by using the get and set methods,
since ArrayList is essentially an array.
107
LinkedList is implemented as a double linked list. Its performance on add and remove is better
than Arraylist, but worse on get and set methods.
Vector is similar with ArrayList, but it is synchronized.
ArrayList is a better choice if your program is thread-safe. Vector and ArrayList require more space
as more elements are added. Vector each time doubles its array size, while ArrayList grow 50
Note: The default initial capacity of an ArrayList is pretty small. It is a good habit to construct the
ArrayList with a higher initial capacity. This can avoid the resizing cost.
40.3
arraylist example
40.4
linkedlist example
Program Creek
108
40.5. VECTOR
As shown in the examples above, they are similar to use. The real difference is their underlying
implementation and their operation complexity.
40.5
vector
Vector is almost identical to ArrayList, and the difference is that Vector is synchronized. Because of
this, it has an overhead than ArrayList. Normally, most Java programmers use ArrayList instead of
Vector because they can synchronize explicitly by themselves.
40.6
* add() in the table refers to add(E e), and remove() refers to remove(int index)
ArrayList has O(n) time complexity for arbitrary indices of add/remove, but O(1) for the
operation at the end of the list.
LinkedList has O(n) time complexity for arbitrary indices of add/remove, but O(1) for operations at end/beginning of the List.
I use the following code to test their performance:
A r r a y L i s t < I n t e g e r > a r r a y L i s t = new A r r a y L i s t < I n t e g e r > ( ) ;
L i n k e d L i s t < I n t e g e r > l i n k e d L i s t = new L i n k e d L i s t < I n t e g e r > ( ) ;
/ / A r r a y L i s t add
long s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 0 0 ; i ++) {
a r r a y L i s t . add ( i ) ;
}
long endTime = System . nanoTime ( ) ;
long d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " A r r a y L i s t add : " + d u r a t i o n ) ;
/ / L i n k e d L i s t add
s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 0 0 ; i ++) {
l i n k e d L i s t . add ( i ) ;
}
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
Program Creek
109
" + duration ) ;
/ / LinkedList get
s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 0 ; i ++) {
linkedList . get ( i ) ;
}
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " L i n k e d L i s t g e t : " + d u r a t i o n ) ;
/ / A r r a y L i s t remove
s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 9 9 9 9 ; i >=0; i ) {
a r r a y L i s t . remove ( i ) ;
}
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " A r r a y L i s t remove :
" + duration ) ;
/ / L i n k e d L i s t remove
s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 9 9 9 9 ; i >=0; i ) {
l i n k e d L i s t . remove ( i ) ;
}
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " L i n k e d L i s t remove : " + d u r a t i o n ) ;
Program Creek
110
L i n k e d L i s t remove : 85768810
The difference of their performance is obvious. LinkedList is faster in add and remove, but slower
in get. Based on the complexity table and testing results, we can figure out when to use ArrayList
or LinkedList. In brief, LinkedList should be preferred if:
there are no large number of random access of element
there are a large number of add/remove operations
Program Creek
111
41
J AVA . U T I L . C O N C U R R E N T M O D I F I C AT I O N E X C E P T I O N
This post shows show to solve the problem of java.util.ConcurrentModificationException for ArrayList.
The error message looks like the following:
E x c e p t i o n i n t h r e a d " main " j a v a . u t i l . C o n c u r r e n t M o d i f i c a t i o n E x c e p t i o n
a t j a v a . u t i l . A r r a y L i s t $ I t r . c h e c k F o r C o m o d i f i c a t i o n ( Unknown Source )
a t j a v a . u t i l . A r r a y L i s t $ I t r . ne xt ( Unknown Source )
...
...
41.1
the problem
You may want to iterate through an ArrayList, and delete some element under some condition. For
example, the following code looks reasonable:
import j a v a . u t i l . A r r a y L i s t ;
import j a v a . u t i l . L i s t ;
public c l a s s AddRemoveListElement {
public s t a t i c void main ( S t r i n g a r g s [ ] ) {
L i s t < S t r i n g > l i s t = new A r r a y L i s t < S t r i n g > ( ) ;
l i s t . add ( "A" ) ;
l i s t . add ( " B " ) ;
for ( String s : l i s t ) {
i f ( s . equals ( "B" ) ) {
l i s t . remove ( s ) ;
}
}
}
}
112
41.2. SOLUTION 1
41.2
solution 1
Iterator can be used to solve this problem. Iterators allow the caller to remove elements from the
underlying collection during the iteration.
I t e r a t o r <String > i t e r = l i s t . i t e r a t o r ( ) ;
while ( i t e r . hasNext ( ) ) {
S t r i n g s t r = i t e r . n ex t ( ) ;
i f ( s t r . equals ( "B" ) )
{
i t e r . remove ( ) ;
}
}
41.3
solution 2
Instead of ArrayList, CopyOnWriteArrayList can be used to solve the problem. CopyOnWriteArrayList is a thread-safe variant of ArrayList in which all mutative operations (add, set, and so on)
are implemented by making a fresh copy of the underlying array.
public s t a t i c void main ( S t r i n g a r g s [ ] ) {
L i s t < S t r i n g > l i s t = new CopyOnWriteArrayList < S t r i n g > ( ) ;
l i s t . add ( "A" ) ;
l i s t . add ( " B " ) ;
for ( String s : l i s t ) {
i f ( s . equals ( "B" ) ) {
l i s t . remove ( s ) ;
}
}
}
41.4
Program Creek
113
l l i s t . add ( "A" ) ;
l l i s t . add ( " B " ) ;
for ( String s : l l i s t ) {
i f ( s . equals ( "B" ) ) {
l l i s t . remove ( s ) ;
}
}
}
The above code is fine, because they do not use array as the underlining data structure.
Program Creek
114
42
HASHSET VS. TREESET VS. LINKEDHASHSET
A Set contains no duplicate elements. That is one of the major reasons to use a set. There are 3
commonly used implementations of Set: HashSet, TreeSet and LinkedHashSet. When and which to
use is an important question. In brief, if you need a fast set, you should use HashSet; if you need
a sorted set, then TreeSet should be used; if you need a set that can be store the insertion order,
LinkedHashSet should be used.
42.1
set interface
Set interface extends Collection interface. In a set, no duplicates are allowed. Every element in
a set must be unique. You can simply add elements to a set, and duplicates will be removed
automatically.
115
42.2
HashSet is Implemented using a hash table. Elements are not ordered. The add, remove, and
contains methods have constant time complexity O(1).
TreeSet is implemented using a tree structure(red-black tree in algorithm book). The elements in
a set are sorted, but the add, remove, and contains methods has time complexity of O(log (n)). It
offers several methods to deal with the ordered set like first(), last(), headSet(), tailSet(), etc.
LinkedHashSet is between HashSet and TreeSet. It is implemented as a hash table with a linked list
running through it, so it provides the order of insertion. The time complexity of basic methods is
O(1).
42.3
treeset example
Program Creek
116
Because TreeSet is sorted, the Dog object need to implement java.lang.Comparables compareTo()
method like the following:
c l a s s Dog implements Comparable<Dog>{
int size ;
public Dog ( i n t s ) {
size = s ;
}
public S t r i n g t o S t r i n g ( ) {
return siz e + " " ;
}
@Override
public i n t compareTo ( Dog o ) {
return siz e o . si ze ;
}
}
42.4
hashset example
HashSet <Dog>
d s e t . add (new
d s e t . add (new
d s e t . add (new
d s e t . add (new
Program Creek
117
Output:
5 3 2 1 4
linkedhashset example
42.6
performance testing
The following method tests the performance of the three class on add() method.
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Random r = new Random ( ) ;
HashSet <Dog> hashSet = new HashSet <Dog > ( ) ;
T r e e S e t <Dog> t r e e S e t = new T r e e S e t <Dog > ( ) ;
LinkedHashSet <Dog> l i n k e d S e t = new LinkedHashSet <Dog > ( ) ;
/ / s t a r t time
long s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 ; i ++) {
int x = r . nextInt (1000 10) + 10;
hashSet . add (new Dog ( x ) ) ;
}
/ / end t i m e
long endTime = System . nanoTime ( ) ;
long d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " HashSet : " + d u r a t i o n ) ;
Program Creek
118
/ / s t a r t time
s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 ; i ++) {
int x = r . nextInt (1000 10) + 10;
t r e e S e t . add (new Dog ( x ) ) ;
}
/ / end t i m e
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " T r e e S e t : " + d u r a t i o n ) ;
/ / s t a r t time
s t a r t T i m e = System . nanoTime ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 ; i ++) {
int x = r . nextInt (1000 10) + 10;
l i n k e d S e t . add (new Dog ( x ) ) ;
}
/ / end t i m e
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " LinkedHashSet : " + d u r a t i o n ) ;
}
From the output below, we can clearly wee that HashSet is the fastest one.
HashSet : 2244768
T r e e S e t : 3549314
LinkedHashSet : 2263320
* The test is not precise, but can reflect the basic idea that TreeSet is much slower because it is
sorted.
Program Creek
119
Program Creek
120
43
H A S H M A P V S . T R E E M A P V S . H A S H TA B L E V S . L I N K E D H A S H M A P
Map is one of the most important data structures. In this tutorial, I will show you how to use
different maps such as HashMap, TreeMap, HashTable and LinkedHashMap.
43.1
map overview
There are 4 commonly used implementations of Map in Java SE - HashMap, TreeMap, Hashtable
and LinkedHashMap. If we use one sentence to describe each implementation, it would be the
following:
HashMap is implemented as a hash table, and there is no ordering on keys or values.
TreeMap is implemented based on red-black tree structure, and it is ordered by the key.
LinkedHashMap preserves the insertion order
Hashtable is synchronized, in contrast to HashMap.
121
43.2. HASHMAP
43.2
hashmap
If key of the HashMap is self-defined objects, then equals() and hashCode() contract need to be
followed.
c l a s s Dog {
String color ;
Dog ( S t r i n g c ) {
color = c ;
}
public S t r i n g t o S t r i n g ( ) {
r e t u r n c o l o r + " dog " ;
}
}
public c l a s s TestHashMap {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
HashMap<Dog , I n t e g e r > hashMap = new HashMap<Dog , I n t e g e r > ( ) ;
Dog d1 = new Dog ( " red " ) ;
Dog d2 = new Dog ( " b l a c k " ) ;
Dog d3 = new Dog ( " white " ) ;
Dog d4 = new Dog ( " white " ) ;
hashMap . put ( d1 ,
hashMap . put ( d2 ,
hashMap . put ( d3 ,
hashMap . put ( d4 ,
10) ;
15) ;
5) ;
20) ;
// print size
System . out . p r i n t l n ( hashMap . s i z e ( ) ) ;
/ / l o o p HashMap
f o r ( Entry <Dog , I n t e g e r > e n t r y : hashMap . e n t r y S e t ( ) ) {
System . out . p r i n t l n ( e n t r y . getKey ( ) . t o S t r i n g ( ) + " " +
e n t r y . getValue ( ) ) ;
}
}
}
Output:
4
white dog
b l a c k dog
red dog
white dog
5
15
10
20
Note here, we add "white dogs" twice by mistake, but the HashMap takes it. This does not make
sense, because now we are confused how many white dogs are really there.
The Dog class should be defined as follows:
Program Creek
122
43.3. TREEMAP
c l a s s Dog {
String color ;
Dog ( S t r i n g c ) {
color = c ;
}
public boolean e q u a l s ( O b j e c t o ) {
r e t u r n ( ( Dog ) o ) . c o l o r == t h i s . c o l o r ;
}
public i n t hashCode ( ) {
return color . length ( ) ;
}
public S t r i n g t o S t r i n g ( ) {
r e t u r n c o l o r + " dog " ;
}
}
The reason is that HashMap doesnt allow two identical elements. By default, the hashCode() and
equals() methods implemented in Object class are used. The default hashCode() method gives
distinct integers for distinct objects, and the equals() method only returns true when two references
refer to the same object. Check out the hashCode() and equals() contract if this is not obvious to
you.
Check out the most frequently used methods for HashMap, such as iteration, print, etc.
43.3
treemap
A TreeMap is sorted by keys. Lets first take a look at the following example to understand the
"sorted by keys" idea.
c l a s s Dog {
String color ;
Dog ( S t r i n g c ) {
color = c ;
}
public boolean e q u a l s ( O b j e c t o ) {
r e t u r n ( ( Dog ) o ) . c o l o r == t h i s . c o l o r ;
}
public i n t hashCode ( ) {
Program Creek
123
43.3. TREEMAP
Output:
E x c e p t i o n i n t h r e a d " main " j a v a . lang . C l a s s C a s t E x c e p t i o n : c o l l e c t i o n . Dog cannot
be c a s t t o j a v a . lang . Comparable
a t j a v a . u t i l . TreeMap . put ( Unknown Source )
a t c o l l e c t i o n . TestHashMap . main ( TestHashMap . j a v a : 3 5 )
Since TreeMaps are sorted by keys, the object for key has to be able to compare with each other,
thats why it has to implement Comparable interface. For example, you use String as key, because
String implements Comparable interface.
Lets change the Dog, and make it comparable.
c l a s s Dog implements Comparable<Dog>{
String color ;
int size ;
Dog ( S t r i n g c , i n t s ) {
color = c ;
size = s ;
}
public S t r i n g t o S t r i n g ( ) {
r e t u r n c o l o r + " dog " ;
}
@Override
Program Creek
124
43.4. HASHTABLE
Output:
red dog 10
b l a c k dog 15
white dog 20
20
10
15
5
The reason is that TreeMap now uses compareTo() method to compare keys. Different sizes make
different dogs!
43.4
hashtable
From Java Doc: The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.
Program Creek
125
43.5. LINKEDHASHMAP
43.5
linkedhashmap
d1
d2
d3
d4
=
=
=
=
new
new
new
new
Output is:
red dog 10
b l a c k dog 15
Program Creek
126
43.5. LINKEDHASHMAP
white dog 20
The difference is that if we use HashMap the output could be the following - the insertion order is
not preserved.
red dog 10
white dog 20
b l a c k dog 15
Program Creek
127
44
E F F I C I E N T C O U N T E R I N J AVA
You may often need a counter to understand the frequency of something (e.g., words) from a
database or text file. A counter can be easily implemented by using a HashMap in Java. This
article compares different approaches to implement a counter. Finally, an efficient one will be concluded.
44.1
In each loop, you check if the key exists or not. If it does, increment the old value by 1, if not, set
it to 1. This approach is simple and straightforward, but it is not the most efficient approach. This
method is considered less efficient for the following reasons:
containsKey(), get() are called twice when a key already exists. That means searching the map
twice.
Since Integer is immutable, each loop will create a new one for increment the old value
128
44.2
Naturally we want a mutable integer to avoid creating many Integer objects. A mutable integer
class can be defined as follows:
c l a s s MutableInteger {
private int val ;
public M u t a b l e I n t e g e r ( i n t v a l ) {
this . val = val ;
}
public i n t g e t ( ) {
return val ;
}
public void s e t ( i n t v a l ) {
this . val = val ;
}
/ / used to p r i n t value c o n v i n e n t l y
public S t r i n g t o S t r i n g ( ) {
return Integer . toString ( val ) ;
}
}
This seems better because it does not require creating many Integer objects any longer. However,
the search is still twice in each loop if a key exists.
44.3
The HashMap.put(key, value) method returns the keys current value. This is useful, because we
can use the reference of the old value to update the value without searching one more time!
HashMap< S t r i n g , MutableInteger > e f f i c i e n t C o u n t e r = new HashMap< S t r i n g ,
MutableInteger > ( ) ;
Program Creek
129
f o r ( S t r i n g a : sArr ) {
M u t a b l e I n t e g e r i n i t V a l u e = new M u t a b l e I n t e g e r ( 1 ) ;
M u t a b l e I n t e g e r oldValue = e f f i c i e n t C o u n t e r . put ( a , i n i t V a l u e ) ;
i f ( oldValue ! = n u l l ) {
i n i t V a l u e . s e t ( oldValue . g e t ( ) + 1 ) ;
}
}
44.4
performance difference
To test the performance of the three different approaches, the following code is used. The performance test is on 1 million times. The raw results are as follows:
Naive Approach : 222796000 Better Approach: 117283000 Efficient Approach: 96374000
The difference is significant - 223 vs. 117 vs. 96. There is huge difference between Naive and Better,
which indicates that creating objects are expensive!
S t r i n g s = " one two t h r e e two t h r e e t h r e e " ;
S t r i n g [ ] sArr = s . s p l i t ( " " ) ;
long s t a r t T i m e = 0 ;
long endTime = 0 ;
long d u r a t i o n = 0 ;
/ / naive approach
s t a r t T i m e = System . nanoTime ( ) ;
HashMap< S t r i n g , I n t e g e r > c o u n t e r = new HashMap< S t r i n g , I n t e g e r > ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 0 0 0 ; i ++)
f o r ( S t r i n g a : sArr ) {
i f ( c o u n t e r . containsKey ( a ) ) {
i n t oldValue = c o u n t e r . g e t ( a ) ;
c o u n t e r . put ( a , oldValue + 1 ) ;
} else {
c o u n t e r . put ( a , 1 ) ;
}
}
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " Naive Approach :
" + duration ) ;
/ / b e t t e r approach
s t a r t T i m e = System . nanoTime ( ) ;
HashMap< S t r i n g , MutableInteger > newCounter = new HashMap< S t r i n g , MutableInteger
>() ;
f o r ( i n t i = 0 ; i < 1 0 0 0 0 0 0 ; i ++)
Program Creek
130
f o r ( S t r i n g a : sArr ) {
i f ( newCounter . containsKey ( a ) ) {
M u t a b l e I n t e g e r oldValue = newCounter . g e t ( a ) ;
oldValue . s e t ( oldValue . g e t ( ) + 1 ) ;
} else {
newCounter . put ( a , new M u t a b l e I n t e g e r ( 1 ) ) ;
}
}
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " B e t t e r Approach :
" + duration ) ;
/ / e f f i c i e n t approach
s t a r t T i m e = System . nanoTime ( ) ;
HashMap< S t r i n g , MutableInteger > e f f i c i e n t C o u n t e r = new HashMap< S t r i n g ,
MutableInteger > ( ) ;
f o r ( i n t i = 0 ; i < 1 0 0 0 0 0 0 ; i ++)
f o r ( S t r i n g a : sArr ) {
M u t a b l e I n t e g e r i n i t V a l u e = new M u t a b l e I n t e g e r ( 1 ) ;
M u t a b l e I n t e g e r oldValue = e f f i c i e n t C o u n t e r . put ( a , i n i t V a l u e ) ;
i f ( oldValue ! = n u l l ) {
i n i t V a l u e . s e t ( oldValue . g e t ( ) + 1 ) ;
}
}
endTime = System . nanoTime ( ) ;
d u r a t i o n = endTime s t a r t T i m e ;
System . out . p r i n t l n ( " E f f i c i e n t Approach :
" + duration ) ;
When you use a counter, you probably also need a function to sort the map by value. You can check
out the frequently used method of HashMap.
44.5
Added a couple tests: 1) Refactored "better approach" to just call get instead of containsKey. Usually,
the elements you want are in the HashMap so that reduces from two searches to one. 2) Added a
test with AtomicInteger, which michal mentioned. 3) Compared to singleton int array, which uses
less memory according to http://amzn.com/0748614079
I ran the test program 3x and took the min to remove variance from other programs. Note that you
cant do this within the program or the results are affected too much, probably due to gc.
Naive: 201716122 Better Approach: 112259166 Efficient Approach: 93066471 Better Approach (without containsKey): 69578496 Better Approach (without containsKey, with AtomicInteger): 94313287
Better Approach (without containsKey, with int[]): 65877234
Better Approach (without containsKey):
Program Creek
131
Program Creek
132
44.6. CONCLUSION
44.6
conclusion
Program Creek
133
45
F R E Q U E N T LY U S E D M E T H O D S O F J AVA H A S H M A P
45.1
I t e r a t o r i t = mp. e n t r y S e t ( ) . i t e r a t o r ( ) ;
while ( i t . hasNext ( ) ) {
Map . Entry p a i r s = (Map . Entry ) i t . n ex t ( ) ;
System . out . p r i n t l n ( p a i r s . getKey ( ) + " = " + p a i r s . getValue ( ) ) ;
}
Map< I n t e g e r , I n t e g e r > map = new HashMap< I n t e g e r , I n t e g e r > ( ) ;
f o r (Map . Entry < I n t e g e r , I n t e g e r > e n t r y : map . e n t r y S e t ( ) ) {
System . out . p r i n t l n ( " Key = " + e n t r y . getKey ( ) + " , Value = " + e n t r y . getValue
() ) ;
}
45.2
print hashmap
134
45.3
There are different ways of sorting HashMap, this way has been voted the most in stackoverflow.
Program Creek
135
46
J AVA T Y P E E R A S U R E M E C H A N I S M
Java Generics is a feature introduced from JDK 5. It allows us to use type parameter when defining
class and interface. It is extensively used in Java Collection framework. The type erasure concept
is one of the most confusing part about Generics. This article illustrates what it is and how to use
it.
46.1
a common mistake
In the following example, the method accept accepts a list of Object as its parameter. In the main
method, it is called by passing a list of String. Does this work?
public c l a s s Main {
public s t a t i c void main ( S t r i n g [ ] a r g s ) throws IOException {
A r r a y L i s t < S t r i n g > a l = new A r r a y L i s t < S t r i n g > ( ) ;
a l . add ( " a " ) ;
a l . add ( " b " ) ;
accept ( al ) ;
}
public s t a t i c void a c c e p t ( A r r a y L i s t <Object > a l ) {
for ( Object o : al )
System . out . p r i n t l n ( o ) ;
}
}
It seems fine since Object is a super type of String obviously. However, that will not work. Compilation will not pass, and give you an error at the line of accept(al); :
The method accept(ArrayList <Object >) in the type Main is not applicable for the arguments (ArrayList <String >)
136
46.2
The reason is type erasure. REMEMBER: Java generics is implemented on the compilation level.
The byte code generated from compiler does not contain type information of generic type for the
run-time execution.
After compilation, both List of Object and List of String become List, and the Object/String type is
not visible for JVM. During compilation stage, compiler finds out that they are not the same, then
gives a compilation error.
46.3
Always remember that Generic is a concept of compile-time. In the example above, since we dont
know ?, we can not add anything to al. To make it work, you can use wildcards.
L i s t < O b j e c t > L i s t can c o n t a i n O b j e c t or i t s subtype
L i s t < ? extends Number > L i s t can c o n t a i n Number or i t s subtypes .
L i s t < ? super Number > L i s t can c o n t a i n Number or i t s s u p e r t y p e s .
46.4
comparisons
Now we know that ArrayList <String >is NOT a subtype of ArrayList <Object >. As a comparison,
you should know that if two generic types have the same parameter, their inheritance relation is
true for the types. For example, ArrayList <String >is subtype of Collection<String>.
Arrays are different. They know and enforce their element types at runtime. This is called reification.
For example, Object[] objArray is a super type of String[] strArr. If you try to store a String into an
Zll
get an ArrayStoreException during run-time.
array of integer, youA
Program Creek
137
47
W H Y D O W E N E E D G E N E R I C T Y P E S I N J AVA ?
Generic types are extensively used in Java collections. Why do we need Generic types in Java?
Understanding this question can help us better understand a lot of related concepts. In this article,
I will use a very short example to illustrate why Generic is useful.
47.1
overview of generics
The goal of implementing Generics is finding bugs in compile-time, other than in run-time. Finding
bugs in compile-time can save time for debugging java program, because compile-time bugs are
much easier to find and fix. Generic types only exist in compile-time. This fact is the most important
thing to remember for learning Java Generics.
47.2
In the following program, the "Room" class defines a member object. We can pass any object to it,
such as String, Integer, etc.
c l a s s Room {
private Object o b j e c t ;
public void add ( O b j e c t o b j e c t ) {
this . object = object ;
}
public O b j e c t g e t ( ) {
return o b j e c t ;
}
}
public c l a s s Main {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Room room = new Room ( ) ;
room . add ( 6 0 ) ;
/ / room . add ( " 6 0 " ) ; / / t h i s w i l l c a u s e a runt i m e e r r o r
I n t e g e r i = ( I n t e g e r ) room . g e t ( ) ;
138
System . out . p r i n t l n ( i ) ;
}
}
The program runs totally fine when we add an integer and cast it. But if a user accidentally add
a string "60" to it, compiler does not know it is a problem. When the program is run, it will get a
ClassCastException.
E x c e p t i o n i n t h r e a d " main " j a v a . lang . C l a s s C a s t E x c e p t i o n : j a v a . lang . S t r i n g cannot
be c a s t t o j a v a . lang . I n t e g e r
a t c o l l e c t i o n . Main . main ( Main . j a v a : 2 1 )
You may wonder why not just declare the field type to be Integer instead of Object. If so, then the
room is not so much useful because it can only store one type of thing.
47.3
Now if someone adds room.add("60"), a compile-time error will be shown like the following:
Program Creek
139
47.4. SUMMARY
We can easily see how this works. In addition, there is no need to cast the result any more from
room.get() since compile knows get() will return an Integer.
47.4
summary
Program Creek
140
48
SET VS. SET<?>
You may know that an unbounded wildcard Set<?>can hold elements of any type, and a raw type
Set can also hold elements of any type. Then what is the difference between them?
48.1
Item 1: Since the question mark ? stands for any type. Set<?>is capable of holding any type of
elements. Item 2: Because we dont know the type of ?, we cant put any element into Set<?>
So a Set<?>can hold any type of element(Item 1), but we cant put any element into it(Item 2). Do
the two statements conflict to each other? Of course they are not. This can be clearly illustrated by
the following two examples:
Item 1 means the following situation:
/ / L e g a l Code
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
HashSet < I n t e g e r > s1 = new HashSet < I n t e g e r >( Arrays . a s L i s t ( 1 , 2 , 3 ) ) ;
p r i n t S e t ( s1 ) ;
}
public s t a t i c void p r i n t S e t ( Set <?> s ) {
for ( Object o : s ) {
System . out . p r i n t l n ( o ) ;
}
}
Since Set<?>can hold any type of elements, we simply use Object in the loop.
Item 2 means the following situation which is illegal:
/ / I l l e g a l Code
public s t a t i c void p r i n t S e t ( Set <?> s ) {
s . add ( 1 0 ) ; / / t h i s l i n e i s i l l e g a l
for ( Object o : s ) {
System . out . p r i n t l n ( o ) ;
}
}
141
Because we dont know the type of <?>exactly, we can not add any thing to it other than null. For
the same reason, we can not initialize a set with Set<?>. The following is illegal:
/ / I l l e g a l Code
Set <?> s e t = new HashSet <? >() ;
48.2
Whats the difference between raw type Set and unbounded wildcard Set<?>?
This method declaration is fine:
public s t a t i c void p r i n t S e t ( S e t s ) {
s . add ( " 2 " ) ;
for ( Object o : s ) {
System . out . p r i n t l n ( o ) ;
}
}
because raw type has no restrictions. However, this will easily corrupt the invariant of collection.
In brief, wildcard type is safe and the raw type is not.
Set<?>.
48.3
When you want to use a generic type, but you dont know or care what the actual type the parameter
is, you can use <?>[1]. It can only be used as parameters.
For example:
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
HashSet < I n t e g e r > s1 = new HashSet < I n t e g e r >( Arrays . a s L i s t ( 1 , 2 , 3 ) ) ;
HashSet < I n t e g e r > s2 = new HashSet < I n t e g e r >( Arrays . a s L i s t ( 4 , 2 , 3 ) ) ;
System . out . p r i n t l n ( getUnion ( s1 , s2 ) ) ;
}
public s t a t i c i n t getUnion ( Set <?> s1 , Set <?> s2 ) {
i n t count = s1 . s i z e ( ) ;
f o r ( O b j e c t o : s2 ) {
i f ( ! s1 . c o n t a i n s ( o ) ) {
count ++;
}
}
r e t u r n count ;
}
Program Creek
142
49
H O W T O C O N V E R T A R R AY T O A R R AY L I S T I N J AVA ?
This article analyzes answers for a top-voted questions on Stack Overflow. The person who asked
this question got a lot of reputation points, which could grant him permissions to do a lot of things
on Stack Overflow. This does not make sense to me, but lets take a look at the question first.
The question is "how to convert the following array to an ArrayList?".
Element [ ] a r r a y = {new Element ( 1 ) ,new Element ( 2 ) ,new Element ( 3 ) } ;
49.1
First, lets take a look at the Java Doc for the constructor method of ArrayList.
ArrayList(Collection <? extends E >c) : Constructs a list containing the elements of the specified
collection, in the order they are returned by the collections iterator.
So what the constructor does is the following: 1. Convert the collection c to an array 2. Copy the
array to ArrayLists own back array called "elementData"
Here is the source code of Contructor of ArrayList.
public A r r a y L i s t ( C o l l e c t i o n <? extends E> c ) {
elementData = c . toArray ( ) ;
s i z e = elementData . l e n g t h ;
i f ( elementData . g e t C l a s s ( ) ! = O b j e c t [ ] . c l a s s )
elementData = Arrays . copyOf ( elementData , s i z e , O b j e c t [ ] . c l a s s ) ;
}
49.2
143
It is not the best, because the size of the list returned from asList() is fixed. We know ArrayList is
essentially implemented as an array, and the list returned from asList() is a fixed-size list backed by
the original array. In this way, if add or remove elements from the returned list, an UnsupportedOperationException will be thrown.
l i s t . add (new Element ( 4 ) ) ;
E x c e p t i o n i n t h r e a d " main " j a v a . lang . C l a s s C a s t E x c e p t i o n : j a v a . u t i l .
A r r a y s $ A r r a y L i s t cannot be c a s t t o j a v a . u t i l . A r r a y L i s t
a t c o l l e c t i o n . ConvertArray . main ( ConvertArray . j a v a : 2 2 )
49.3
another solution
49.4
The problem is not hard, but interesting. Every Java programmer knows ArrayList, but its easy to
make such a mistake. I guess that is why this question is so popular. If a similar question asked
about a Java library in a specific domain, it would be less likely to become so popular.
There are several answers that provide the same solution. This is also true for a lot of other questions
on Stack Overflow, I guess people just dont care what others say if they would like to answer a
question!
Program Creek
144
50
Y E T A N O T H E R J AVA PA S S E S B Y R E F E R E N C E O R B Y VA L U E ?
This is a classic interview question which confuses novice Java developers. In this post I will use an
example and some diagram to demonstrate that: Java is pass-by-value.
50.1
some definitions
Pass by value: make a copy in memory of the actual parameters value that is passed in. Pass by
reference: pass a copy of the address of the actual parameter.
Java is always pass-by-value. Primitive data types and object reference are just values.
50.2
Since Java is pass-by-value, its not hard to understand the following code will not swap anything.
swap ( Type arg1 , Type arg2 ) {
Type temp = arg1 ;
arg1 = arg2 ;
arg2 = temp ;
}
50.3
Java manipulates objects by reference, and all object variables are references. However, Java doesnt
pass method arguments by reference, but by value.
Question is: why the member value of the object can get changed?
145
Code:
c l a s s Apple {
public S t r i n g c o l o r = " red " ;
}
public c l a s s Main {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Apple apple = new Apple ( ) ;
System . out . p r i n t l n ( apple . c o l o r ) ;
changeApple ( apple ) ;
System . out . p r i n t l n ( apple . c o l o r ) ;
}
public s t a t i c void changeApple ( Apple apple ) {
apple . c o l o r = " green " ;
}
}
Since the orignal and copied reference refer the same object, the member value gets changed.
Output:
red
Program Creek
146
green
Program Creek
147
51
J AVA R E F L E C T I O N T U T O R I A L
51.1
what is reflection?
"Reflection is commonly used by programs which require the ability to examine or modify the
runtime behavior of applications running in the Java virtual machine." This concept is often mixed
with introspection. The following are their definitions from Wiki:
Introspection is the ability of a program to examine the type or properties of an object at
runtime.
Reflection is the ability of a program to examine and modify the structure and behavior of an
object at runtime.
From their definitions, introspection is a subset of reflection. Some languages support introspection,
but do not support reflection, e.g., C++.
Introspection Example: The instanceof operator determines whether an object belongs to a particular
class.
i f ( o b j i n s t a n c e o f Dog ) {
Dog d = ( Dog ) o b j ;
d . bark ( ) ;
}
148
Reflection Example: The Class.forName() method returns the Class object associated with the
class/interface with the given name(a string and full qualified name). The forName method causes
the class with the name to be initialized.
/ / with r e f l e c t i o n
Class <?> c = C l a s s . forName ( " c l a s s p a t h . and . classname " ) ;
O b j e c t dog = c . newInstance ( ) ;
Method m = c . getDeclaredMethod ( " bark " , new Class < ? > [ 0 ] ) ;
m. invoke ( dog ) ;
In Java, reflection is more about introspection, because you can not change structure of an object.
There are some APIs to change accessibilities of methods and fields, but not structures.
51.2
When the Spring context processes this <bean >element, it will use Class.forName(String) with the
argument "com.programcreek.Foo" to instantiate that Class. It will then again use reflection to get
the appropriate setter for the <property >element and set its value to the specified value.
The same mechanism is also used for Servlet web applications:
<servlet >
< s e r v l e t name>someServlet </ s e r v l e t name>
< s e r v l e t c l a s s >com . programcreek . W h y R e f l e c t i o n S e r v l e t </ s e r v l e t c l a s s >
<servlet >
Program Creek
149
51.3
How to use reflection API can be shown by using a small set of typical code examples.
Example 1: Get class name from object
package m y r e f l e c t i o n ;
import j a v a . lang . r e f l e c t . Method ;
public c l a s s R e f l e c t i o n H e l l o W o r l d {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Foo f = new Foo ( ) ;
System . out . p r i n t l n ( f . g e t C l a s s ( ) . getName ( ) ) ;
}
}
c l a s s Foo {
public void p r i n t ( ) {
System . out . p r i n t l n ( " abc " ) ;
}
}
Output:
m y r e f l e c t i o n . Foo
Program Creek
150
abc
Program Creek
151
/ / get a l l constructors
C o n s t r u c t o r <?> cons [ ] = c . g e t C o n s t r u c t o r s ( ) ;
try {
f 1 = ( Foo ) cons [ 0 ] . newInstance ( ) ;
f 2 = ( Foo ) cons [ 1 ] . newInstance ( " abc " ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
f1 . print ( ) ;
f2 . print ( ) ;
}
}
c l a s s Foo {
String s ;
public Foo ( ) { }
public Foo ( S t r i n g s ) {
t h i s . s=s ;
}
public void p r i n t ( ) {
System . out . p r i n t l n ( s ) ;
}
}
Output:
null
abc
In addition, you can use Class instance to get implemented interfaces, super class, declared field,
etc.
Example 5: Change array size though reflection
package m y r e f l e c t i o n ;
import j a v a . lang . r e f l e c t . Array ;
public c l a s s R e f l e c t i o n H e l l o W o r l d {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
int [ ] intArray = { 1 , 2 , 3 , 4 , 5 } ;
i n t [ ] newIntArray = ( i n t [ ] ) changeArraySize ( intArray , 1 0 ) ;
p r i n t ( newIntArray ) ;
String [ ] a t r = { " a " , "b" , " c " , "d" , " e " } ;
S t r i n g [ ] s t r 1 = ( S t r i n g [ ] ) changeArraySize ( a t r , 1 0 ) ;
print ( str1 ) ;
}
Program Creek
152
51.4. SUMMARY
/ / change array s i z e
public s t a t i c O b j e c t changeArraySize ( O b j e c t obj , i n t l e n ) {
Class <?> a r r = o b j . g e t C l a s s ( ) . getComponentType ( ) ;
O b j e c t newArray = Array . newInstance ( a r r , l e n ) ;
/ / do a r r a y c o p y
i n t co = Array . getLength ( o b j ) ;
System . arraycopy ( obj , 0 , newArray , 0 , co ) ;
r e t u r n newArray ;
}
// print
public s t a t i c void p r i n t ( O b j e c t o b j ) {
Class <?> c = o b j . g e t C l a s s ( ) ;
i f ( ! c . isArray ( ) ) {
return ;
}
System . out . p r i n t l n ( " \nArray l e n g t h : " + Array . getLength ( o b j ) ) ;
f o r ( i n t i = 0 ; i < Array . getLength ( o b j ) ; i ++) {
System . out . p r i n t ( Array . g e t ( obj , i ) + " " ) ;
}
}
}
Output:
Array
1 2 3
Array
a b c
51.4
l e n g t h : 10
4 5 0 0 0 0 0
l e n g t h : 10
d e null null null null null
summary
The above code examples shows a very small set of functions provided by Java reflection. Reading
those examples may only give you a taste of Java reflection, you may want to Read more information
on Oracle website.
Program Creek
153
52
S A S I M P L E E X A M P L E
H O W T O D E S I G N A J AVA F R A M E W O R K ? A
You may be curious about how framework works? A simple framework example will be made here
to demonstrate the idea of frameworks.
52.1
goal of a framework
First of all, why do we need a framework other than just a normal library? The goal of framework
is defining a process which let developers implement certain functions based on individual requirements. In other words, framework defines the skeleton and developers fill in the flash when using
it.
52.2
In the following example, the first 3 classes are defined as a part of framework and the 4th class is
the client code of the framework.
Main.java is the entry point of the framework. This can not be changed.
/ / i m a g i n e t h i s i s t h e e n t r y p o i n t f o r a f r a m e w o r k , i t can n o t b e c h a n g e d
public c l a s s Main {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
Human h = new Human(new Walk ( ) ) ;
h . doMove ( ) ;
}
}
Move.java is the Hook. A hook is where developers can define / extend functions based on their
own requirements.
public a b s t r a c t c l a s s Move {
public a b s t r a c t void a c t i o n ( ) ;
}
Human.java is the Template, which reflects the idea of how the framework works.
public c l a s s Human {
p r i v a t e Move move ;
154
52.3. CONCLUSION
This simple framework allows and requires developers to extend "Move" class. Actually, in this
simple framework, action() method is the only thing developers are able to change.
Inside of the implementation, different "action" can be programmed to different purpose. E.g. the
example below print "5 miles per hour", of course, you can redefine it as "50 miles per hour".
public c l a s s Walk extends Move {
@Override
public void a c t i o n ( ) {
/ / TODO Auto g e n e r a t e d method s t u b
System . out . p r i n t l n ( " 5 m i l e s per hour i t i s slow ! " ) ;
}
}
52.3
conclusion
The example here just shows how a simple Template and Hook works. A real framework is more
complicated than this. Not only does it contain other relations like template-temple relation, but
also very complex process about how to efficiently improve performance and programming usability.
Program Creek
155
53
W H Y D O W E N E E D J AVA W E B F R A M E W O R K S L I K E S T R U T S 2 ?
There are various kinds of Java web frameworks, such as Spring MVC, JavaServer Faces, Struts 2,
etc. For a newbie programmer, there is an exponential learning curve.
Why do I need Java web frameworks like Struts 2? This question can be answered by starting from
answering how the Servlet API works.
Here is a post which contains code about how to simply program with Servlet API. You would
never use this to really program a large project, but its good to take a look how it looks like
originally.
Here is a simple Servlet which process request from client and generate response html.
import
import
import
import
import
import
import
j a v a . i o . IOException ;
java . io . PrintWriter ;
javax . s e r v l e t . ServletConfig ;
javax . s e r v l e t . ServletException ;
javax . s e r v l e t . http . HttpServlet ;
javax . s e r v l e t . http . HttpServletRequest ;
javax . s e r v l e t . http . HttpServletResponse ;
p r o t e c t e d void doPost ( H t t p S e r v l e t R e q u e s t r e q u e s t , H t t p S e r v l e t R e s p o n s e
response ) throws S e r v l e t E x c e p t i o n , IOException {
/ / Get t h e v a l u e o f f o r m p a r a m e t e r
S t r i n g name = r e q u e s t . getParameter ( " name " ) ;
S t r i n g welcomeMessage = " Welcome " +name ;
/ / S e t t h e c o n t e n t t y p e (MIME Type ) o f t h e r e s p o n s e .
response . setContentType ( " t e x t /html " ) ;
P r i n t W r i t e r out = response . g e t W r i t e r ( ) ;
/ / W r i t e t h e HTML t o t h e r e s p o n s e
out . p r i n t l n ( " <html > " ) ;
156
157
public void d e s t r o y ( ) {
}
}
This is very simple, real usage wont be easy like this. A real servlet has more work to do as
summarized below:
Binding request parameters to Java types. String name = request.getParameter("name");
Validating data. E.g. There should not be numbers in peoples name.
Making calls to business logic. E.g. Process the name for some purposes.
Communicate with the data layer. E.g. Store user data.
Rendering presentation layer (HTML, and so on). E.g. Return results for client browser.
Of course, we can do all of those by ourselves, which is totally possible. However, that would take
a lot of time. And very often, those functions are common features which can be implemented in
some certain approach. Struts 2 is such an approach. It provides a standard way to implement those
common functions following MVC design patterns.
Here is my previous post about a simple Struts2 application.
Program Creek
54
J V M R U N - T I M E D ATA A R E A S
This is my note of reading JVM specification. I draw a diagram which helps me understand.
54.1
Data Areas for each individual thread include program counter register, JVM Stack, and Native
Method Stack. They are all created when a new thread is created.
A
JVM Stack: It
Program Counter Register: it is used to control each execution of each thread. A
contains frames which is demonstrated in the diagram below.
A
Native Method Stack: it is used to support native methods, i.e., non-Java language methods. A
158
54.2
codeA
Runtime Constant Pool: It is a per-class or per-interface run-time representation of the constant_pool
table in a class file. It contains several kinds of constants, ranging from numeric literals known at
compile-time to method and field references that must be resolved at run-time.
Stack contains Frames, and a frame is pushed to the stack when a method is invoked. A frame
contains local variable array, Operand Stack, Reference to Constant Pool.
For more information, please go to the offical JVM specification site.
Program Creek
159
55
H O W D O E S J AVA H A N D L E A L I A S I N G ?
55.1
Aliasing means there are multiple aliases to a location that can be updated, and these aliases have
different types.
In the following example, a and b are two variable names that have two different types A and B. B
extends A.
B [ ] b = new B [ 1 0 ] ;
A[ ] a = b ;
a [ 0 ] = new A( ) ;
b [ 0 ] . methodParent ( ) ;
The pointed memory location are pointed by both a and b. During run-time, the actual object stored
determines which method to call.
55.2
If you copy this code to your eclipse, there will be no compilation errors.
class A {
160
The reason is that Java handles aliasing during run-time. During run-time, it knows that the first
element should be a B object, instead of A.
Therefore, it only runs correctly if it is changed to:
B [ ] b = new B [ 1 0 ] ;
A[ ] a = b ;
a [ 0 ] = new B ( ) ;
b [ 0 ] . methodParent ( ) ;
Program Creek
161
56
W H AT D O E S A J AVA A R R AY L O O K L I K E I N M E M O R Y ?
Arrays in Java store one of two things: either primitive values (int, char, ...) or references (a.k.a
pointers).
When an object is creating by using "new", memory is allocated on the heap and a reference is
returned. This is also true for arrays, since arrays are objects.
56.1
single-dimension array
i n t a r r [ ] = new i n t [ 3 ] ;
The int[] arr is just the reference to the array of 3 integer. If you create an array with 10 integer, it is
the same - an array is allocated and a reference is returned.
56.2
two-dimensional array
How about 2-dimensional array? Actually, we can only have one dimensional arrays in Java. 2D
arrays are basically just one dimensional arrays of one dimensional arrays.
i n t [ ] [ ] a r r = new i n t [ 3 ] [ ] ;
a r r [ 0 ] = new i n t [ 3 ] ;
a r r [ 1 ] = new i n t [ 5 ] ;
a r r [ 2 ] = new i n t [ 4 ] ;
162
56.3
Arrays are also objects in Java, so how an object looks like in memory applies to an array.
As we know that JVM runtime data areas include heap, JVM stack, and others. For a simple example
as follows, lets see where the array and its reference are stored.
class A {
int x ;
int y ;
}
...
public void m1 ( ) {
int i = 0;
m2 ( ) ;
}
public void m2 ( ) {
A a = new A( ) ;
}
...
With the above declaration, lets invoke m1() and see what happens:
When m1 is invoked, a new frame (Frame-1) is pushed into the stack, and local variable i is
also created in Frame-1.
Program Creek
163
Then m2 is invoked inside of m1, another new frame (Frame-2) is pushed into the stack. In
m2, an object of class A is created in the heap and reference variable is put in Frame-2. Now,
at this point, the stack and heap looks like the following:
Arrays are treated the same way like objects, so how array locates in memory is straight-forward.
Program Creek
164
57
T H E I N T R O D U C T I O N O F J AVA M E M O R Y L E A K S
One of the most significant advantages of Java is its memory management. You simply create objects
and Java Garbage Collector takes care of allocating and freeing memory. However, the situation is
not as simple as that, because memory leaks frequently occur in Java applications.
This tutorial illustrates what is memory leak, why it happens, and how to prevent them.
57.1
Definition of Memory Leak: objects are no longer being used by the application, but Garbage
Collector can not remove them because they are being referenced.
To understand this definition, we need to understand objects status in memory. The following
diagram illustrates what is unused and what is unreferenced.
From the diagram, there are referenced objects and unreferenced objects. Unreferenced objects will
be garbage collected, while referenced objects will not be garbage collected. Unreferenced objects are
surely unused, because no other objects refer to it. However, unused objects are not all unreferenced.
Some of them are being referenced! Thats where the memory leaks come from.
165
57.2
Lets take a look at the following example and see why memory leaks happen. In the example
below, object A refers to object B. As lifetime (t1 - t4) is much longer than Bs (t2 - t3). When B is no
longer being used in the application, A still holds a reference to it. In this way, Garbage Collector
can not remove B from memory. This would possibly cause out of memory problem, because if A
does the same thing for more objects, then there would be a lot of objects that are uncollected and
consume memory space.
It is also possible that B hold a bunch of references of other objects. Those objects referenced by B
will not get collected either. All those unused objects will consume precious memory space.
57.3
The following are some quick hands-on tips for preventing memory leaks.
Pay attention to Collection classes, such as HashMap, ArrayList, etc., as they are common
places to find memory leaks. When they are declared static, their life time is the same as the
life time of the application.
Pay attention to event listeners and callbacks. A memory leak may occur if a listener is registered but not unregistered when the class is not being used any longer.
"If a class manages its own memory, the programer should be alert for memory leaks."[1]
Often times member variables of an object that point to other objects need to be null out.
Program Creek
166
57.4. A LITTLE QUIZ: WHY SUBSTRING() METHOD IN JDK 6 CAN CAUSE MEMORY LEAKS?
57.4
a little quiz: why substring() method in jdk 6 can cause memory leaks?
To answer this question, you may want to read Substring() in JDK 6 and 7.
Program Creek
167
58
W H AT I S S E R V L E T C O N TA I N E R ?
In this post, I write a little bit about the basic ideas of web server, Servlet container and its relation
with JVM. I want to show that Servlet container is nothing more than a Java program.
58.1
To know what is a Servlet container, we need to know what is a Web Server first.
A web server uses HTTP protocol to transfer data. In a simple situation, a user type in a URL (e.g.
www.programcreek.com/static.html) in browser (a client), and get a web page to read. So what
the server does is sending a web page to the client. The transformation is in HTTP protocol which
specifies the format of request and response message.
58.2
As we see here, the user/client can only request static webpage from the server. This is not good
enough, if the user wants to read the web page based on his input. The basic idea of Servlet
container is using Java to dynamically generate the web page on the server side. So servlet container
is essentially a part of a web server that interacts with the servlets.
168
58.3
what is a servlet?
Servlet is an interface defined in javax.servlet package. It declares three essential methods for the life
S init(), service(), and destroy(). They are implemented by every servlet(defined
cycle of a servlet A
in SDK or self-defined) and are invoked at specific times by the server.
The init() method is invoked during initialization stage of the servlet life cycle. It is passed
an object implementing the javax.servlet.ServletConfig interface, which allows the servlet to
access initialization parameters from the web application.
The service() method is invoked upon each request after its initialization. Each request is
serviced in its own separate thread. The web container calls the service() method of the
servlet for every request. The service() method determines the kind of request being made
and dispatches it to an appropriate method to handle the request.
The destroy() method is invoked when the servlet object should be destroyed. It releases the
resources being held.
From the life cycle of a servlet object, we can see that servlet classes are loaded to container by
class loader dynamically. Each request is in its own thread, and a servlet object can serve multiple
threads at the same time(thread not safe). When it is no longer being used, it should be garbage
collected by JVM.
Like any Java program, the servlet runs within a JVM. To handle the complexity of HTTP requests,
Z creation, executhe servlet container comes in. The servlet container is responsible for servletsA
tion and destruction.
58.4
Program Creek
169
The servlet is dynamically retrieved and loaded into the address space of the container, if it is
not in the container.
The container invokes the init() method of the servlet for initialization(invoked once when the
servlet is loaded first time)
The container invokes the service() method of the servlet to process the HTTP request, i.e.,
read data in the request and formulate a response. The servlet remains in the containers
address space and can process other HTTP requests.
Web server return the dynamically generated results to the correct location
The six steps are marked on the following diagram:
58.5
Using servlets allows the JVM to handle each request within a separate Java thread, and this is
one of the key advantage of Servlet container. Each servlet is a Java class with special elements
responding to HTTP requests. The main function of Servlet contain is to forward requests to correct
servlet for processing, and return the dynamically generated results to the correct location after
the JVM has processed them. In most cases servlet container runs in a single JVM, but there are
solutions when container need multiple JVMs.
Program Creek
170
59
W H AT I S A S P E C T - O R I E N T E D P R O G R A M M I N G ?
What is Aspect-Oriented Programming(AOP)? By using the diagram below, the concept can be
understood in a few seconds.
59.1
First take a took at the diagram below, and think about what could be the problem.
1. Code tangling: the logging code is mixed with business logic. 2. Code scattering: caused by
identical code put in every module.
171
The logging function is a called "cross-cutting concern". That is, a function that is used in many other
modules, such as authentication, logging, performance, error checking, data persistence, storage
management, to name just a few.
By using Object-Oriented Programming (OOP), we can define low coupling and high cohesion
system. However, when it comes to cross-cutting concerns, it does not handle it well for the reason
that it does not relation between handle core concerns and cross-cutting concerns.
59.2
Program Creek
172
60
L I B R A RY V S . F R A M E W O R K ?
What is the difference between a Java Library and a framework? The two concepts are important
but sometimes confusing for Java developers.
60.1
The key difference between a library and a framework is "Inversion of Control". When you call
a method from a library, you are in control. But with a framework, the control is inverted: the
framework calls you.
A library is just a collection of class definitions. The reason behind is simply code reuse, i.e. get the
code that has already been written by other developers. The classes and methods normally define
specific operations in a domain specific area. For example, there are some libraries of mathematics
which can let developer just call the function without redo the implementation of how an algorithm
works.
In framework, all the control flow is already there, and theres a bunch of predefined white spots that
you should fill out with your code. A framework is normally more complex. It defines a skeleton
where the application defines its own features to fill out the skeleton. In this way, your code will be
called by the framework when appropriately. The benefit is that developers do not need to worry
about if a design is good or not, but just about implementing domain specific functions.
173
60.2
their relation
Both of them defined API, which is used for programmers to use. To put those together, we can think
of a library as a certain function of an application, a framework as the skeleton of the application,
and an API is connector to put those together. A typical development process normally starts with
a framework, and fill out functions defined in libraries through API.
60.3
examples
Program Creek
174
61
J AVA A N D C O M P U T E R S C I E N C E C O U R S E S
A good programmer does not only know how to program a task, but also knows why it is done that
way and how to do it efficiently. Indeed, we can find almost any code by using Google, knowing why
it is done that way is much more difficult than knowing how to do it, especially when something
goes wrong.
To understand Java design principles behind, Computer Science(CS) courses are helpful. Here is the
diagram showing the relation between Java and Operating System, Networks, Artificial Intelligence,
Compiler, Algorithm, and Logic.
175
176
Program Creek
62
H O W J AVA C O M P I L E R G E N E R AT E C O D E F O R O V E R L O A D E D A N D
OVERRIDDEN METHODS?
From the compiler perspective, how is code generated for the correct function calls?
Static overloading is not hard to implement. When processing the declaration of an overloaded
function, a new binding maps it to a different implementation. During the type checking process,
compiler analyzes the parameters real type to determine which function to use.
177
178
Program Creek
63
T O P 1 0 M E T H O D S F O R J AVA A R R AY S
The following are top 10 methods for Java Array. They are the most voted questions from stackoverflow.
63.1
declare an array
S t r i n g [ ] aArray = new S t r i n g [ 5 ] ;
S t r i n g [ ] bArray = { " a " , " b " , " c " , " d " , " e " } ;
S t r i n g [ ] cArray = new S t r i n g [ ] { " a " , " b " , " c " , " d " , " e " } ;
63.2
int [ ] intArray = { 1 , 2 , 3 , 4 , 5 } ;
S t r i n g i n t A r r a y S t r i n g = Arrays . t o S t r i n g ( i n t A r r a y ) ;
/ / print d i r e c t l y will print r e f e r e n c e value
System . out . p r i n t l n ( i n t A r r a y ) ;
/ / [ I@7150bd4d
System . out . p r i n t l n ( i n t A r r a y S t r i n g ) ;
/ / [1 , 2 , 3 , 4 , 5]
63.3
String [ ] stringArray = { " a " , "b" , " c " , "d" , " e " } ;
A r r a y L i s t < S t r i n g > a r r a y L i s t = new A r r a y L i s t < S t r i n g >( Arrays . a s L i s t ( s t r i n g A r r a y ) ) ;
System . out . p r i n t l n ( a r r a y L i s t ) ;
// [a , b , c , d , e]
63.4
String [ ] stringArray = { " a " , "b" , " c " , "d" , " e " } ;
boolean b = Arrays . a s L i s t ( s t r i n g A r r a y ) . c o n t a i n s ( " a " ) ;
System . out . p r i n t l n ( b ) ;
/ / true
179
63.5
int [ ] intArray = { 1 , 2 , 3 , 4 , 5 } ;
i n t [ ] i n t A r r a y 2 = { 6 , 7 , 8 , 9 , 10 } ;
/ / Apache Commons Lang l i b r a r y
i n t [ ] combinedIntArray = A r r a y U t i l s . addAll ( intArray , i n t A r r a y 2 ) ;
63.6
method (new S t r i n g [ ] { " a " , " b " , " c " , " d " , " e " } ) ;
63.7
63.8
String [ ] stringArray = { " a " , "b" , " c " , "d" , " e " } ;
A r r a y L i s t < S t r i n g > a r r a y L i s t = new A r r a y L i s t < S t r i n g >( Arrays . a s L i s t ( s t r i n g A r r a y ) ) ;
S t r i n g [ ] s t r i n g A r r = new S t r i n g [ a r r a y L i s t . s i z e ( ) ] ;
a r r a y L i s t . toArray ( s t r i n g A r r ) ;
for ( String s : stringArr )
System . out . p r i n t l n ( s ) ;
63.9
63.10
reverse an array
int [ ] intArray = { 1 , 2 , 3 , 4 , 5 } ;
ArrayUtils . reverse ( intArray ) ;
System . out . p r i n t l n ( Arrays . t o S t r i n g ( i n t A r r a y ) ) ;
/ / [5 , 4 , 3 , 2 , 1]
63.11
int [ ] intArray = { 1 , 2 , 3 , 4 , 5 } ;
i n t [ ] removed = A r r a y U t i l s . removeElement ( intArray , 3 ) ; / / c r e a t e a new a r r a y
System . out . p r i n t l n ( Arrays . t o S t r i n g ( removed ) ) ;
Program Creek
180
63.12
byte [ ] b y t e s = B y t e B u f f e r . a l l o c a t e ( 4 ) . p u t I n t ( 8 ) . a r r a y ( ) ;
f o r ( byte t : b y t e s ) {
System . out . format ( " 0x%x " , t ) ;
}
Program Creek
181
64
T O P 1 0 Q U E S T I O N S O F J AVA S T R I N G S
The following are top 10 frequently asked questions about Java Strings.
64.1
In brief, "==" tests if references are equal and equals() tests if values are equal. Unless you want to
check if two strings are the same object, you should always use equals(). It would be better if you
know the concept of string interning.
64.2
Strings are immutable, which means once they are created, they will stay unchanged until Garbage
Collector kicks in. With an array, you can explicitly change its elements. In this way, security
sensitive information(e.g. password) will not be present anywhere in the system.
64.3
Yes to version 7. From JDK 7, we can use string as switch condition. Before version 6, we can not
use string as switch condition.
/ / java 7 only !
switch ( s t r . toLowerCase ( ) ) {
case " a " :
value = 1 ;
break ;
case " b " :
value = 2 ;
break ;
}
64.4
182
i n t n = I n t e g e r . p a r s e I n t ( " 10 " ) ;
64.6
In JDK 6, the substring() method gives a window to an array of chars which represents the existing
String, but do not create a new one. To create a new string represented by a new char array, you can
do add an empty string like the following:
s t r . s u b s t r i n g (m, n ) + " "
This will create a new char array that represents the new string. The above approach sometimes can
make your code faster, because Garbage Collector can collect the unused large string and keep only
the sub string.
In Oracle JDK 7, substring() creates a new char array, not uses the existing one. Check out the
diagram for showing substring() difference between JDK 6 and JDK 7.
64.7
String vs StringBuilder: StringBuilder is mutable, which means you can modify it after its creation.
StringBuilder vs StringBuffer: StringBuffer is synchronized, which means it is thread-safe but slower
than StringBuilder.
64.8
In Python, we can just multiply a number to repeat a string. In Java, we can use the repeat() method
of StringUtils from Apache Commons Lang package.
S t r i n g s t r = " abcd " ;
String repeated = S t r i n g U t i l s . repeat ( str , 3 ) ;
/ / abcdabcdabcd
Program Creek
183
64.9
64.10
64.11
one more do you know how to detect if a string contains only uppercase
letter?
Program Creek
184
65
T O P 1 0 Q U E S T I O N S F O R J AVA R E G U L A R E X P R E S S I O N
This post summarizes the top questions asked about Java regular expressions. As they are most
frequently asked, you may find that they are also very useful.
1. How to extract numbers from a string?
One common question of using regular expression is to extract all the numbers into an array of
integers.
In Java, m
. eans a range of digits (0-9). Using the predefined classes whenever possible will make
your code easier to read and eliminate errors introduced by malformed character classes. Please
refer to Predefined character classes for more details. Please note the first backslash in .. If you
are using an escaped construct within a string literal, you must precede the backslash with another
backslash for the string to compile. Thats why we need to use
d.
L i s t < I n t e g e r > numbers = new L i n k e d L i s t < I n t e g e r > ( ) ;
P a t t e r n p = P a t t e r n . compile ( " \\d+ " ) ;
Matcher m = p . matcher ( s t r ) ;
while (m. f i n d ( ) ) {
numbers . add ( I n t e g e r . p a r s e I n t (m. group ( ) ) ) ;
}
Zt
want empty lines, you can use, which is also my favourite way:
But if you donA
S t r i n g . s p l i t ( " [\\ r\\n]+ " )
185
186
A more robust way, which is really system independent, is as follows. But remember, you will still
get empty lines if two newline characters are placed side by side.
S t r i n g . s p l i t ( System . g e t P r o p e r t y ( " l i n e . s e p a r a t o r " ) ) ;
3. Importance of Pattern.compile()
A regular expression, specified as a string, must first be compiled into an instance of Pattern class.
Pattern.compile() method is the only way to create a instance of object. A typical invocation sequence is thus
P a t t e r n p = P a t t e r n . compile ( " ab " ) ;
Matcher matcher = p . matcher ( " aaaaab " ) ;
a s s e r t matcher . matches ( ) == t r u e ;
Essentially, Pattern.compile() is used to transform a regular expression into an Finite state machine
(see Compilers: Principles, Techniques, and Tools (2nd Edition)). But all of the states involved in
performing a match resides in the matcher. By this way, the Pattern p can be reused. And many
matchers can share the same pattern.
Matcher anotherMatcher = p . matcher ( " aab " ) ;
a s s e r t anotherMatcher . matches ( ) == t r u e ;
Pattern.matches() method is defined as a convenience for when a regular expression is used just
once. This method still uses compile() to get the instance of a Pattern implicitly, and matches a
string. Therefore,
boolean b = P a t t e r n . matches ( " ab " , " aaaaab " ) ;
is equivalent to the first code above, though for repeated matches it is less efficient since it does not
allow the compiled pattern to be reused.
4. How to escape text for regular expression?
In general, regular expression uses "to escape constructs, but it is painful to precede the backslash
with another backslash for the Java string to compile. There is another way for users to pass string
Literals to the Pattern, like "$5". Instead of writing
$5 or [$]5, we can type
P a t t e r n . quote ( " $5 " ) ;
Program Creek
187
This is the language of all non-empty strings consisting of some number of as followed by an equal
number of bs, like ab, aabb, and aaabbb. This language can be show to be context-free grammar S
E
aSb | ab, and therefore a non-regular language.
However, Java regex implementations can recognize more than just regular languages. That is,
they are not "regular" by formal language theory definition. Using lookahead and self-reference
matching will achieve it. Here I will give the final regular expression first, then explain it a little
bit. For a comprehensive explanation, I would refer you to read How can we match an bn with Java
regex.
P a t t e r n p = P a t t e r n . compile ( " ( ? x ) ( ? : a ( ? = a (\\1?+b ) ) ) +\\1 " ) ;
/ / true
System . out . p r i n t l n ( p . matcher ( " aaabbb " ) . matches ( ) ) ;
// false
System . out . p r i n t l n ( p . matcher ( " aaaabbb " ) . matches ( ) ) ;
// false
System . out . p r i n t l n ( p . matcher ( " aaabbbb " ) . matches ( ) ) ;
// false
System . out . p r i n t l n ( p . matcher ( " caaabbb " ) . matches ( ) ) ;
Instead of explaining the syntax of this complex regular expression, I would rather say a little bit
how it works.
In the first iteration, it stops at the first a then looks ahead (after skipping some as by using
a*) whether there is a b. This was achieved by using (?:a(?= a*( extbackslash extbackslash
1?+b))). If it matches, extbackslash 1, the self-reference matching, will matches the very inner
parenthesed elements, which is one single b in the first iteration.
In the second iteration, the expression will stop at the second a, then it looks ahead (again
skipping as) to see if there will be b. But this time, extbackslash extbackslash 1+b is actually
equivalent to bb, therefore two bs have to be matched. If so, extbackslash 1 will be changed to
bb after the second iteration.
In the nth iteration, the expression stops at the nth a and see if there are n bs ahead.
By this way, the expression can count the number of as and match if the number of bs followed by
a is same.
7. How to replace 2 or more spaces with single space in string and delete leading spaces only?
String.replaceAll() replaces each substring that matches the given regular expression with the given
replacement. "2 or more spaces" can be expressed by regular expression [ ]+. Therefore, the following code will work. Note that, the solution wont ultimately remove all leading and trailing
whitespaces. If you would like to have them deleted, you can use String.trim() in the pipeline.
S t r i n g l i n e = " aa bbbbb
ccc
d ";
/ / " aa bbbbb c c c d "
System . out . p r i n t l n ( l i n e . r e p l a c e A l l ( " [\\ s ]+ " , " " ) ) ;
Program Creek
188
/ / true
System . out .
/ / true
System . out .
/ / true
System . out .
// false
System . out .
/ / true
System . out .
// false
System . out .
// false
System . out .
p r i n t l n ( prime ( 2 ) ) ;
p r i n t l n ( prime ( 3 ) ) ;
p r i n t l n ( prime ( 5 ) ) ;
p r i n t l n ( prime ( 8 ) ) ;
p r i n t l n ( prime ( 1 3 ) ) ;
p r i n t l n ( prime ( 1 4 ) ) ;
p r i n t l n ( prime ( 1 5 ) ) ;
}
public s t a t i c boolean prime ( i n t n ) {
r e t u r n ! new S t r i n g (new char [ n ] ) . matches ( " . ? | ( . . + ? ) \\1+ " ) ;
}
The function first generates n number of characters and tries to see if that string matches .?|(..+?)
1+. If it is prime, the expression will return false and the ! will reverse the result.
The first part .? just tries to make sure 1 is not primer. The magic part is the second part where
backreference is used. (..+?)
1+ first try to matches n length of characters, then repeat it several times by
1+.
By definition, a prime number is a natural number greater than 1 that has no positive divisors other
than 1 and itself. That means if a=n*m then a is not a prime. n*m can be further explained "repeat
n m times", and that is exactly what the regular expression does: matches n length of characters by
using (..+?), then repeat it m times by using
1+. Therefore, if the pattern matches, the number is not prime, otherwise it is. Remind that ! will
reverse the result.
9. How to split a comma-separated string but ignoring commas in quotes?
You have reached the point where regular expressions break down. It is better and more neat to
write a simple splitter, and handles special cases as you wish.
Alternative, you can mimic the operation of finite state machine, by using a switch statement or
if-else. Attached is a snippet of code.
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
S t r i n g l i n e = " aaa , bbb , \ " c , c \ " , dd ; dd , \ " e , e " ;
L i s t < S t r i n g > t o k s = splitComma ( l i n e ) ;
for ( String t : toks ) {
System . out . p r i n t l n ( " > " + t ) ;
}
}
p r i v a t e s t a t i c L i s t < S t r i n g > splitComma ( S t r i n g s t r ) {
int s t a r t = 0;
Program Creek
65.1
Program Creek
189
66
T O P 1 0 Q U E S T I O N S A B O U T J AVA E X C E P T I O N S
This article summarizes the top 10 frequently asked questions and answers about Java exceptions.
For example, whats the best practice for exception management?
66.1
In brief, checked exceptions must be explicitly caught in a method or declared in the methods
throws clause. Unchecked exceptions are caused by problems that can not be solved, such as
dividing by zero, null pointer, etc. Checked exceptions are especially important because you expect
other developers who use your API to know how to handle the exceptions.
For example, IOException is a commonly used checked exception and RuntimeException is an
unchecked exception. You can check out the exception hierarchy diagram before reading the
rest.
66.2
If an exception can be properly handled then it should be caught, otherwise, it should be thrown.
66.3
In the following code, the string s declared in try block can not be used in catch clause. The code
does not pass compilation.
try {
F i l e f i l e = new F i l e ( " path " ) ;
F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( f i l e ) ;
String s = " inside " ;
} c a t c h ( FileNotFoundException e ) {
e . printStackTrace ( ) ;
System . out . p r i n t l n ( s ) ;
}
190
The reason is that you dont know where in the try block the exception would be thrown. It is quite
possible that the exception is thrown before the object is declared. This is true for this particular
example.
66.4
They actually throw different exceptions. This is a problem of JDK, so it does not worth too much
thinking.
Integer . parseInt ( null ) ;
/ / throws j a v a . lang . NumberFormatException : n u l l
Double . parseDouble ( n u l l ) ;
/ / throws java . lang . NullPointerException
66.5
66.6
The answer is YES. As long as those exceptions can trace back to the same node in the hierarchy,
you can use that one only.
66.7
The answer is YES. Constructor is a special kind of method. Here is a code example.
66.8
Program Creek
F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( f i l e 1 ) ;
} c a t c h ( FileNotFoundException e ) {
e . printStackTrace ( ) ;
} finally {
try {
F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( f i l e 2 ) ;
} c a t c h ( FileNotFoundException e ) {
e . printStackTrace ( ) ;
}
}
}
But to have better code readability, you should wrap the embedded try-catch block as a new method,
and then put the method invocation in the finally clause.
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
F i l e f i l e 1 = new F i l e ( " path1 " ) ;
F i l e f i l e 2 = new F i l e ( " path2 " ) ;
try {
F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( f i l e 1 ) ;
} c a t c h ( FileNotFoundException e ) {
e . printStackTrace ( ) ;
} finally {
methodThrowException ( ) ;
}
}
66.9
Yes, it can.
66.10
There are so many time code segments like the following occur. If properly handling exceptions are
so important, why developers keep doing that?
try {
...
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
Program Creek
192
67
T O P 1 0 Q U E S T I O N S A B O U T J AVA C O L L E C T I O N S
The following are the most popular questions of Java collections asked and discussed on Stackoverflow. Before you look at those questions, its a good idea to see the class hierarchy diagram.
67.1
ArrayList is essentially an array. Its elements can be accessed directly by index. But if the array is
full, a new larger array is needed to allocate and moving all elements to the new array will take O(n)
time. Also adding or removing an element needs to move existing elements in an array. This might
be the most disadvantage to use ArrayList.
LinkedList is a double linked list. Therefore, to access an element in the middle, it has to search
from the beginning of the list. On the other hand, adding and removing an element in LinkedList
is quicklier, because it only changes the list locally.
In summary, the worst case of time complexity comparison is as follows:
| A r r a y l i s t | LinkedList
g e t ( index )
|
O( 1 )
|
O( n )
add ( E )
|
O( n )
|
O( 1 )
add ( E , index )
|
O( n )
|
O( n )
remove ( index )
|
O( n )
|
O( n )
I t e r a t o r . remove ( ) |
O( n )
|
O( 1 )
I t e r a t o r . add ( E )
|
O( n )
|
O( 1 )
Despite the running time, memory usage should be considered too especially for large lists. In
LinkedList, every node needs at least two extra pointers to link the previous and next nodes; while
in ArrayList, only an array of elements is needed.
More comparisons between list.
193
67.2. EFFICIENT EQUIVALENT FOR REMOVING ELEMENTS WHILE ITERATING THE COLLECTION
67.2
The only correct way to modify a collection while iterating is using Iterator.remove()(). For example,
I t e r a t o r <Integer > i t r = l i s t . i t e r a t o r ( ) ;
while ( i t r . hasNext ( ) ) {
/ / do s o m e t h i n g
i t r . remove ( ) ;
}
You will get a ConcurrentModificationException by running the above code. This is because an
iterator has been generated (in for statement) to traverse over the list, but at the same time the list
is changed by Iterator.remove(). In Java, "it is not generally permissible for one thread to modify a
collection while another thread is iterating over it."
67.3
The easiest way might be using ArrayUtils in Apache Commons Lang library.
i n t [ ] a r r a y = A r r a y U t i l s . t o P r i m i t i v e ( l i s t . toArray (new I n t e g e r [ 0 ] ) ) ;
In JDK, there is no short-cut. Note that you can not use List.toArray(), because that will convert List
to Integer[]. The correct way is following,
i n t [ ] a r r a y = new i n t [ l i s t . s i z e ( ) ] ;
f o r ( i n t i = 0 ; i < l i s t . s i z e ( ) ; i ++) {
array [ i ] = l i s t . get ( i ) ;
}
67.4
The easiest way might still be using ArrayUtils in Apache Commons Lang library, like below.
L i s t l i s t = Arrays . a s L i s t ( A r r a y U t i l s . t o O b j e c t ( a r r a y ) ) ;
Program Creek
194
67.5
Again, you can use third-party package, like Guava or Apache Commons Lang to fullfil this function.
Both provide a filter() method (in Collections2 of Guava and in CollectionUtils of Apache). The
filter() method will return elements that match a given Predicate.
In JDK, things become harder. A good news is that in Java 8, Predicate will be added. But for now
you have to use Iterator to traverse the whole collection.
I t e r a t o r <Integer > i t r = l i s t . i t e r a t o r ( ) ;
while ( i t r . hasNext ( ) ) {
i n t i = i t r . ne xt ( ) ;
i f ( i > 5) { / / f i l t e r a l l i n t s b i g g e r than 5
i t r . remove ( ) ;
}
}
Of course you can mimic the way of what Guava and Apache did, by introducing a new interface
Predicate. That might also be what most advanced developers will do.
public i n t e r f a c e P r e d i c a t e <T> {
boolean t e s t ( T o ) ;
}
public s t a t i c <T> void f i l t e r ( C o l l e c t i o n <T> c o l l e c t i o n , P r e d i c a t e <T> p r e d i c a t e )
{
i f ( ( c o l l e c t i o n ! = n u l l ) && ( p r e d i c a t e ! = n u l l ) ) {
I t e r a t o r <T> i t r = c o l l e c t i o n . i t e r a t o r ( ) ;
while ( i t r . hasNext ( ) ) {
T o b j = i t r . ne xt ( ) ;
i f ( ! predicate . t e s t ( obj ) ) {
i t r . remove ( ) ;
}
}
}
}
67.6
There are two ways to do so, depending on how you want equal defined. The first piece of code
puts a list into a HashSet. Duplication is then identified mostly by hashCode(). In most cases, it will
work. But if you need to specify the way of comparison, it is better to use the second piece of code
where you can define your own comparator.
Program Creek
195
67.7
This question is quite related to the above one. If you dont care the ordering of the elements in the
ArrayList, a clever way is to put the list into a set to remove duplication, and then to move it back
to the list. Here is the code
A r r a y L i s t l i s t = . . . / / i n i t i a l a l i s t w i t h d u p l i c a t e e l e m e n t s
Set < I n t e g e r > s e t = new HashSet < I n t e g e r >( l i s t ) ;
l i s t . clear () ;
l i s t . addAll ( s e t ) ;
If you DO care about the ordering, there is no short-cut way. Two loops are needed at least.
67.8
sorted collection
There are a couple of ways to maintain a sorted collection in Java. All of them provide a collection
in natural ordering or by the specified comparator. By natural ordering, you also need to implement
the Comparable interface in the elements.
Collections.sort() can sort a List. As specified in the javadoc, this sort is stable, and guarantee
n log(n) performance.
PriorityQueue provides an ordered queue. The difference between PriorityQueue and Collections.sort() is that, PriorityQueue maintain an order queue at all time, but you can only
get the head element from the queue. You can not randomly access its element like PriorityQueue.get(4).
If there is no duplication in the collection, TreeSet is another choice. Same as PriorityQueue,
it maintains the ordered set at all time. You can get the lowest and highest elements from the
TreeSet. But you still cannot randomly access its element.
In a short, Collections.sort() provides a one-time ordered list. PriorityQueue and TreeSet maintain
ordered collections at all time, in the cost of no indexed access of elements.
67.9
Program Creek
196
67.10. COLLECTIONS.COPY
the existing empty instance. If you are familiar Singleton in the design pattern, you should know
what I mean. So this will give you better performance if called frequently.
67.10
collections.copy
There are two ways to copy a source list to a destination list. One way is to use ArrayList constructor
A r r a y L i s t < I n t e g e r > d s t L i s t = new A r r a y L i s t < I n t e g e r >( s r c L i s t ) ;
The other is to use Collections.copy() (as below). Note the first line, we allocate a list at least as long
as the source list, because in the javadoc of Collections, it says The destination list must be at least
as long as the source list.
A r r a y L i s t < I n t e g e r > d s t L i s t = new A r r a y L i s t < I n t e g e r >( s r c L i s t . s i z e ( ) ) ;
C o l l e c t i o n s . copy ( d s t L i s t , s r c L i s t ) ;
Both methods are shallow copy. So what is the difference between these two methods?
First, Collections.copy() wont reallocate the capacity of dstList even if dstList does not have
enough space to contain all srcList elements. Instead, it will throw an IndexOutOfBoundsException. One may question if there is any benefit of it. One reason is that it guarantees the
method runs in linear time. Also it makes suitable when you would like to reuse arrays rather
than allocate new memory in the constructor of ArrayList.
Collections.copy() can only accept List as both source and destination, while ArrayList accepts
Collection as the parameter, therefore more general.
Program Creek
197
68
T O P 9 Q U E S T I O N S A B O U T J AVA M A P S
In general, Map is a data structure consisting of a set of key-value pairs, and each key can only
appears once in the map. This post summarizes Top 9 FAQ of how to use Java Map and its implemented classes. For sake of simplicity, I will use generics in examples. Therefore, I will just write
Map instead of specific Map. But you can always assume that both the K and V are comparable,
which means K extends Comparable and V extends Comparable.
68.1
In Java, Map interface provides three collection views: key set, value set, and key-value set. All of
them can be converted to List by using a constructor or addAll() method. The following snippet of
code shows how to construct an ArrayList from a map.
/ / key l i s t
L i s t k e y L i s t = new A r r a y L i s t (map . keySet ( ) ) ;
/ / value l i s t
L i s t v a l u e L i s t = new A r r a y L i s t (map . v a l u e S e t ( ) ) ;
/ / key v a l u e l i s t
L i s t e n t r y L i s t = new A r r a y L i s t (map . e n t r y S e t ( ) ) ;
68.2
Iterating over every pair of key-value is the most basic operation to traverse a map. In Java, such
pair is stored in the map entry called Map.Entry. Map.entrySet() returns a key-value set, therefore
the most efficient way of going through every entry of a map is
f o r ( Entry e n t r y : map . e n t r y S e t ( ) ) {
/ / get key
K key = e n t r y . getKey ( ) ;
/ / get value
V value = e n t r y . getValue ( ) ;
}
198
while ( i t r . hasNext ( ) ) {
Entry e n t r y = i t r . n ext ( ) ;
/ / get key
K key = e n t r y . getKey ( ) ;
/ / get value
V value = e n t r y . getValue ( ) ;
}
68.3
Sorting a map on the keys is another frequent operation. One way is to put Map.Entry into a list,
and sort it using a comparator that sorts the value.
L i s t l i s t = new A r r a y L i s t (map . e n t r y S e t ( ) ) ;
C o l l e c t i o n s . s o r t ( l i s t , new Comparator ( ) {
@Override
public i n t compare ( Entry e1 , Entry e2 ) {
r e t u r n e1 . getKey ( ) . compareTo ( e2 . getKey ( ) ) ;
}
}) ;
The other way is to use SortedMap, which further provides a total ordering on its keys. Therefore
all keys must either implement Comparable or be accepted by the comparator.
One implementing class of SortedMap is TreeMap. Its constructor can accept a comparator. The
following code shows how to transform a general map to a sorted map.
SortedMap sortedMap = new TreeMap (new Comparator ( ) {
@Override
public i n t compare (K k1 , K k2 ) {
r e t u r n k1 . compareTo ( k2 ) ;
}
}) ;
sortedMap . p u t A l l (map) ;
68.4
Putting the map into a list and sorting it works on this case too, but we need to compare Entry.getValue() this time. The code below is almost same as before.
L i s t l i s t = new A r r a y L i s t (map . e n t r y S e t ( ) ) ;
C o l l e c t i o n s . s o r t ( l i s t , new Comparator ( ) {
@Override
public i n t compare ( Entry e1 , Entry e2 ) {
Program Creek
199
We can still use a sorted map for this question, but only if the values are unique too. Under such
condition, you can reverse the key=value pair to value=key. This solution has very strong limitation
therefore is not really recommended by me.
68.5
When you expect a map to remain constant, its a good practice to copy it into an immutable map.
Such defensive programming techniques will help you create not only safe for use but also safe for
thread maps.
To initialize a static/immutable map, we can use a static initializer (like below). The problem of this
code is that, although map is declared as static final, we can still operate it after initialization, like
Test.map.put(3,"three");. Therefore it is not really immutable. To create an immutable map using a
static initializer, we need an extra anonymous class and copy it into a unmodifiable map at the last
step of initialization. Please see the second piece of code. Then, an UnsupportedOperationException
will be thrown if you run Test.map.put(3,"three");.
public c l a s s T e s t {
p r i v a t e s t a t i c f i n a l Map map ;
static {
map = new HashMap ( ) ;
map . put ( 1 , " one " ) ;
map . put ( 2 , " two " ) ;
}
}
public c l a s s T e s t {
p r i v a t e s t a t i c f i n a l Map map ;
static {
Map aMap = new HashMap ( ) ;
aMap . put ( 1 , " one " ) ;
aMap . put ( 2 , " two " ) ;
map = C o l l e c t i o n s . unmodifiableMap ( aMap ) ;
}
}
Guava libraries also support different ways of intilizaing a static and immutable collection. To
learn more about the benefits of Guavas immutable collection utilities, see Immutable Collections
Explained in Guava User Guide.
Program Creek
200
68.6
There are three main implementations of Map interface in Java: HashMap, TreeMap, and Hashtable.
The most important differences include:
The order of iteration. HashMap and HashTable make no guarantees as to the order of the
map; in particular, they do not guarantee that the order will remain constant over time. But
TreeMap will iterate the whole entries according the "natural ordering" of the keys or by a
comparator.
key-value permission. HashMap allows null key and null values. HashTable does not allow
null key or null values. If TreeMap uses natural ordering or its comparator does not allow null
keys, an exception will be thrown.
Synchronized. Only HashTable is synchronized, others are not. Therefore, "if a thread-safe
implementation is not needed, it is recommended to use HashMap in place of HashTable."
A more complete comparison is
| HashMap | HashTable | TreeMap
i t e r a t i o n order | no
| no
| yes
n u l l keyvalue
| yes yes | nono
| noyes
synchronized
| no
| yes
| no
time performance | O( 1 )
| O( 1 )
| O( l o g n )
implementation
| buckets | buckets
| redb l a c k t r e e
Read more about HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap.
68.7
Sometimes, we need a set of key-key pairs, which means the maps values are unique as well as
keys (one-to-one map). This constraint enables to create an "inverse lookup/view" of a map. So we
can lookup a key by its value. Such data structure is called bidirectional map, which unfortunetely
is not supported by JDK.
68.8
both apache common collections and guava provide implementation of bidirectional map, called bidimap and bimap, respectively. both enforce the restriction that there is a 1:1 relation between keys and values. 7. shallow
copy of a map
Most implementation of a map in java, if not all, provides a constructor of copy of another map.
But the copy procedure is not synchronized. That means when one thread copies a map, another
one may modify it structurally. To [prevent accidental unsynchronized copy, one should use Collections.synchronizedMap() in advance.
Map copiedMap = C o l l e c t i o n s . synchronizedMap (map) ;
Program Creek
201
68.9. FOR THIS REASON, I WILL NOT EVEN TELL YOU HOW TO USE CLONE() METHOD TO COPY A MAP. 8. CREA
Another interesting way of shallow copy is by using clone() method. However it is NOT even
recommended by the designer of Java collection framework, Josh Bloch. In a conversation about
"Copy constructor versus cloning", he said
I often provide a public clone method on concrete classes because people expect it. ... Its a shame that
Cloneable is broken, but it happens. ... Cloneable is a weak spot, and I think people should be aware of its
limitations.
68.9
for this reason, i will not even tell you how to use clone() method to copy
a map. 8. create an empty map
THE END
Program Creek