Java Strings
Java Strings
Java Strings
• Substring methods
Declaration
• Like any object, a string can be created using new as in the following example:
String str1 = new String(“Hello dear”);
• However, as an extra support, Java allows String object to be created without the use of new, as in:
String str2=”How are you”;
Examples:
String sub = greeting.substring(0, 4); “Hell”
String w = greeting.substring(7, 12); “World”
String tail = greeting.substring(7); “World!”
CONCATENATION OPERATOR
• Another common operation on String is concatenation.
• As another special support for String, Java overloaded the + operator to be used to concatenate two
String objects to get a bigger one.
String firstName = “Amr”;
String lastName = “Al-Ibrahim”;
String fullName = lastName+” “+firstName;
“Al-Ibrahim Amr”
• If one of the operands of the + operator is a string, the other is automatically converted to string and
the two strings are then concatenated.
String course = “ICS”;
int code = 102;
String courseCode = course+code “ICS102”
• You need to be careful with concatenation operator. For example, what do you this the following print?
System.out.println(“Sum =“+5+6);
STRINGS ARE IMMUTABLE
• Another special feature of Strings is that they are immutable. That is, once a string object is
created, its content cannot be changed. For example, consider the following:
String str1 = “Hello World”;
str1 = str1.substring(4);
• Instead of changing the str1 object, another object is created. The former is garbage collected,
thus, the reference to the former is lost.
• The fact that Strings are immutable allows the Java system to process Strings very efficiently.
• For example, consider the following:
String str1 = “Hello”;
String str2 = “Hello”;
• We would expect the following
• The Java system is smart enough to know that the two strings are identical and allocates same
memory location for the two objects
METHODS OF THE STRING CLASS
• In addition to the substring methods, several predefined methods are provided in the
built-in String class. Some of these are:
String toUpperCase() returns a new String, equivalent to the Upper/lower case of this String
String toLowerCase()
boolean equals(s) returns true if s the same as this String.
boolean equalsIgnoreCase(s)
int compareTo(String s) returns +ve number, 0, or -ve number if this String is greater than, equal to or less
int compareToIngoreCase(s) than s.
char charAt(index) returns the char in this String, at the index position.
int indexOf(ch) Returns the index of the first / last occurrence of ch in this string, If not fount-1 is
int lastIndexOf(ch) returned
String trim() returns a String, obtained by removing spaces from the start and end of this string.
static String valueOf (any primitive Returns a String representation of the argument
type)
String concat(s) equivalent to + symbol
EXAMPLE USING METHODS OF STRING CLASS
• The following program generates a password for a student using his initials and age.
public class MakePassword {
public static void main(String[] args) {
String firstName = "Amr";
String middleName = "Samir";
String lastName = "Ibrahim";
//extract initials
String initials =
firstName.substring(0,1)+
middleName.substring(0,1)+
lastName.substring(0,1);
//append age
int age = 20;
String password = initials.toLowerCase()+age;
System.out.println("Your Password ="+password);
}
}
STRINGBUFFER CLASS
• A thread-safe, mutable sequence of characters. A string buffer is like a String, but can be modified.
At any point in time it contains some particular sequence of characters, but the length and
content of the sequence can be changed through certain method calls.
• String buffers are safe for use by multiple threads. The principal operations on a StringBuffer are
the append and insert methods. Each effectively converts a given datum to a string and then
appends or inserts the characters of that string to the string buffer. The append method always
adds these characters at the end of the buffer; the insert method adds the characters at a
specified point.
• For example, if z refers to a string buffer object whose current contents are "start", then the
method call z.append("le") would cause the string buffer to contain "startle", whereas z.insert(4,
"le") would alter the string buffer to contain "starlet".
• In general, if sb refers to an instance of a StringBuffer, then sb.append(x) has the same effect as
sb.insert(sb.length(), x).
STRING BUFFER CONSTRUCTORS
Constructor and Description
StringBuffer()Constructs a string buffer with no characters in it and an initial capacity
of 16 characters.
StringBuffer(CharSequence seq)Constructs a string buffer that contains the same
characters as the specified CharSequence.
StringBuffer(int capacity)Constructs a string buffer with no characters in it and the
specified initial capacity.
StringBuffer(String str)Constructs a string buffer initialized to the contents of the
specified string.
import java.io.*;
class GFG {
public static void main(String[] args)
{
StringBuffer s = new StringBuffer(“Hello world");
s.replace(5, 8, “oo");
System.out.println(s);
}
}
STRINGBUILDER CLASS
• StringBuilder objects are like String objects, except that they can be modified. Hence Java
StringBuilder class is also used to create mutable (modifiable) string object. StringBuilder is same
as StringBuffer except for one important difference. StringBuilder is not synchronized, which
means it is not thread safe. At any point, the length and content of the sequence can be changed
through method invocations.
Constructors of StringBuilder class:
• StringBuilder ( ) : Constructs a string builder with no characters in it and an initial capacity of 16
characters.
• StringBuilder ( int capacity ) : Constructs a string builder with no characters in it and an initial
capacity specified by the capacity argument.
• StringBuilder ( String str ) : Constructs a string builder initialized to the contents of the specified
string. The initial capacity of the string builder is 16 plus the length of the string argument.
Methods of StringBuilder class
• append() : The append() method concatenates the given argument(string representation) to the
end of the invoking StringBuilder object. StringBuilder class has several overloaded append()
method. Few are:
{ A();
newThreads {
{ A(); A1(); A2(); A3(); { A1(); A2(); A3() };
B1(); B2(); } {B1(); B2() }
}
}
THREAD ECOLOGY IN A JAVA PROGRAM
started by B thread
lifetime of C thread
2. DEFINE AND LAUNCH A JAVA
THREAD
• Each Java Run time thread is encapsulated in a java.lang.Thread instance.
• Two ways to define a thread:
1. Extend the Thread class
2. Implement the Runnable interface :
package java.lang;
public interface Runnable { public void run() ; }
• Steps for extending the Thread class:
1. Subclass the Thread class;
2. Override the default Thread method run(), which is the entry point of the thread, like the main(String[]) method
in a java program.
DEFINE A THREAD
// Example:
public class Print2Console extends Thread {
public void run() { // run() is to a thread what main() is to a java program
for (int b = -128; b < 128; b++) out.println(b); }
… // additional methods, fields …
}
• Impement the Runnable interface if you need a parent class:
// by extending JTextArea we can reuse all existing code of JTextArea
public class Print2GUI extend JTextArea implement Runnable {
public void run() {
for (int b = -128; b < 128; b++) append( Integer.toString(b) + “\n” ); }
}
HOW TO LAUNCH A THREAD
1. create an instance of [ a subclass of ] of Thread, say thread.
1. Thread thread = new Print2Console();
2. Thread thread = new Thread( new Print2GUI( .. ) );
2. call its start() method, thread.start();. // note: not call run() !!
Ex:
– Printer2Console t1 = new Print2Console(); // t1 is a thread instance !
– t1.start() ; // this will start a new thread, which begins its execution by calling
t1.run()
– … // parent thread continue immediately here without waiting for the child
thread to complete its execution. cf: t1.run();
– Print2GUI jtext = new Print2GUI();
– Thread t2 = new Thread( jtext);
– t2.start();
– …
THE JAVA.LANG.THREAD CONSTRUCTORS
// Public Constructors
• Thread([ ThreadGroup group,] [ Runnable target, ]
[ String name ] );
– Instances :
– Thread();
– Thread(Runnable target);
– Thread(Runnable target, String name);
– Thread(String name);
– Thread(ThreadGroup group, Runnable target);
– Thread(ThreadGroup group, Runnable target, String name);
– Thread(ThreadGroup group, String name);
// name is a string used to identify the thread instance
// group is the thread group to which this thred belongs.
S O M E T H R E A D P R O P E R T Y A C C E S S M ET H O D S
• boolean isAlive()
– Tests if this thread has been started and has not yet died. .
• boolean isDaemon()
– Tests if this thread is a daemon thread.
• boolean isInterrupted()
– Tests whether this thread has been interrupted.
S TAT E M ET H O D S F O R C U R R E N T T H R E A D A C C E S S E S
public class Thread { .. // enum in 1.5 is a special class for finite type.
public static enum State { //use Thread.State for referring to this nested class
NEW, // after new Thread(), but before start().
RUNNABLE, // after start(), when running or ready
BLOCKED, // blocked by monitor lock
// blocked by a synchronized method/block
WAITING, // waiting for to be notified; no time out set
// wait(), join()
TIMED_WAITING, // waiting for to be notified; time out set
// sleep(time), wait(time), join(time)
TERMINATED // complete execution or after stop()
}…
}
The life cycle of a Java thread
runnable
get the lock blocked/waiting
start() resume()
new Thread(…)
not-running thread t terminates
(ready) sleep done
o.notify(), o.notifyAll()
interrupt()
(set bit) interrupt()
yield(), or
preempty scheduled
by OS (throw exception)
by OS
o.wait()
sleep(…)
running t.join()
stop(),
terminated suspend()
run() exits
blocked by lock
normally or
abnormally
S TAT E T R A N S I T I O N M E T H O D S F O R T H R E A D
do some work;
sleep( … ); // give another thread a chance to work
}
}
catch (InterruptedException e) { // if waked-up by interrupt() then continue here
… // thread interrupted during sleep or wait }
}
• Note: the interrupt() method will not throw an InterruptedException if the thread is not
blocked/waiting. In such case the thread needs to call the static interrupted() method to find out
if it was recently interrupted. So we should rewrite the while loop by
while ( ! interrupted() && moreWorkToDo() ) { … }
INTERRUPT-REL ATED METHODS
• void interrupt()
– send an Interrupt request to a thread.
– the “interrupted” status of the thread is set to true.
– if the thread is blocked by sleep(), wait() or join(), the The interrupted status of the thread is
cleared and an InterruptedException is thrown.
– conclusion: runnable ==> “interrupted” bit set but no Exception thrown.
– not runnable ==> Exception thrown but “interrupted” bit not set
• static boolean interrupted() // destructive query
– Tests whether the current thread (self) has been interrupted.
– reset the “interrupted” status to false.
• boolean isInterrupted() // non-destructive query
– Tests whether this thread has been interrupted without changing the “interrupted” status.
– may be used to query current executing thread or another non-executing thread. e.g.
if( t1.isInterrupted() | Thread.currentThread()...) …
5. THREAD SYNCHRONIZATION
• Problem with any multithreaded Java program :
– Two or more Thread objects access the same pieces of data.
• too little or no synchronization ==> there is inconsistency, loss or
corruption of data.
• too much synchronization ==> deadlock or system frozen.
• In between there is unfair processing where several threads can
starve another one hogging all resources between themselves.
MULTITHREADING MAY INCUR INCONSISTENCY : AN EX AMPLE
Two concurrent deposits of 50 into an account with 0 initial balance.:
void deposit(int amount) {
int x = account.getBalance();
x += amount;
account.setBalance(x); }
• deposit(50) : // deposit 1
deposit(50) : // deposit 2
x = account.getBalance() //1
x += 50; //2 x = account.getBalance() //4
account.setBalance(x) //3 x += 50; //5
The execution sequence: account.setBalance(x) //6
1,4,2,5,3,6 will result in unwanted result !!
Final balance is 50 instead of 100!!
SYNCHRONIZED METHODS AND STATEMENTS
• Java use the monitor concept to achieve mutual exclusion and synchronization
between threads.
• Synchronized methods /statements guarantee mutual exclusion.
– Mutual exclusion may cause a thread to be unable to complete its task. So
monitor allow a thread to wait until state change and then continue its work.
• wait(), notify() and notifyAll() control the synchronization of threads.
– Allow one thread to wait for a condition (logical state) and another to set it and
then notify waiting threads.
– condition variables => instance boolean variables
– wait => wait();
– notifying => notify(); notifyAll();
TYPICAL USAGE
synchronized void doWhenCondition() {
while ( !condition )
wait(); // wait until someone notifies us of changes in condition
… // do what needs to be done when condition is true
}
synchronized void changeCondition {
// change some values used in condition test
notify(); // Let waiting threads know something changed
}
Note: A method may serve both roles; it may need some condition to occur to do something and its
action my cause condition to change.
PRODUCER/CONSUMER PROBLEM
• Thread priorities
– public final int getPriority();
– public final void setPriority();
– get/set priority bttween MIN_PRIORITY and MAX_PRIORITY
– default priority : NORMAL_PRIORITY
• Daemon threads:
– isDaemon(), setDaemon(boolean)
– A Daemon thread is one that exists for service of other threads.
– The JVM exits if all threads in it are Daemon threads.
– setDaemon(.) must be called before the thread is started.
• public static boolean holdsLock(Object obj)
– check if this thread holds the lock on obj.
– ex: synchronized( e ) { Thread.holdLock(e) ? true:false // is true … }
THREAD GROUPS
• Every Java thread is a member of a thread group.
• Thread groups provide a mechanism for collecting multiple threads into a single object and
manipulating those threads all at once, rather than individually.
• When creating a thread,
– let the runtime system put the new thread in some reasonable default group ( the current thread group)
or
– explicitly set the new thread's group.
• you cannot move a thread to a new group after the thread has been created.
– when launched, main program thread belongs to main thread group.
CREATING A THREAD EXPLICITLY IN A GROUP
public Thread(ThreadGroup group, Runnable runnable)
public Thread(ThreadGroup group, String name)
public Thread(ThreadGroup group, Runnable runnable, String name)
currentGroup.enumerate(listOfThreads);
for (int i = 0; i < numThreads; i++)
System.out.println("Thread #" + i + " = " +
listOfThreads[i].getName());
}
}
METHODS THAT OPERATE ON THE THREADGROUP
• getMaxPriority(), setMaxPriority(int)
• isDaemon(), setDaemon(boolean)
– A Daemon thread group is one that destroys itself when its last thread/group is destroyed.
• getName() // name of the thread
• getParent() and parentOf(ThreadGroup) // boolean
• toString()
• activeCount(), activeGroupCount()
• // # of active descendent threads, and groups