Making A Collection Read-Only

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 37

Making a Collection Read-Only

Making a collection read-only


involves wrapping the collection in
another object whose mutation
methods all throw
UnsupportedOperationException.
List stuff =
Arrays.asList(new String[]{"a",
"b"});

// Make a list read-only


List list = new
ArrayList(stuff);
list =
Collections.unmodifiableList(lis
t);

try {
// Try modifying the
list
list.set(0, "new
value");
} catch
(UnsupportedOperationException
e) {
// Can't modify
}

// Make a set read-only


Set set = new
HashSet(stuff);
set =
Collections.unmodifiableSet(set)
;

// Make a map read-only


Map map = new HashMap();
// Add key/value pairs ...
map =
Collections.unmodifiableMap(map)
;

/*
Java Comparable example.
This Java Comparable example
describes how
java.util.Comparable interface
is implemented to compare user
defined classe's objects.
*/
import java.util.*;
/*
Comparable interface is used to
make user defined class's
objects comparable.
This interface declares one
method compareTo(Object object)
and determines how ojbects can
be compared to each other.
*/
/*
Implement java.util.Comparable
interface to make class objects
comparable.
*/
class Employee implements
Comparable{
private int age;
public void setAge(int age){
this.age=age;
}
public int getAge(){
return this.age;
}
/*
Signature of compareTo method
is.
public int compareTo(Object
object).
compareTo method should return 0
if both objects are equal, 1 if
first grater than other and -1
if first less than the other
object of the same class.
*/
public int compareTo(Object
otherEmployee){
/*
If passed object is of type
other than Employee, throw
ClassCastException.
*/
if( ! ( otherEmployee instanceof
Employee ) ){
throw new
ClassCastException("Invalid
object");
}
int age = ( (Employee)
otherEmployee ).getAge();
if( this.getAge() > age )
return 1;
else if ( this.getAge() < age )
return -1;
else
return 0;
}
}
public class
JavaComparableExample{
public static void main(String
args[]){
/*
Create two different Employee
objects, so that we can compare
both.
*/
Employee one = new Employee();
one.setAge(40);
Employee two = new Employee();
one.setAge(30);
/*
Use compareTo method to
determine which employee is
younger
*/
if( one.compareTo(two) > 0 ) {
System.out.println("Employee one
is elder than employee two !");
} else if( one.compareTo(two) <
0 ) {
System.out.println("Employee one
is younger than employee
two !");
} else( one.compareTo(two) == 0
) {
System.out.println("Both
employees are same !");
}
}
}
/*
OUTPUT of the above given Java
Comparable Example would be :
Employee one is elder than
employee two !
*/

Catching all Errors and Exceptions


All errors and exceptions extend
from Throwable. By catching
Throwable, it is possible to handle
all unexpected conditions.
There are several scenarios where
it is good practice to catch
Throwable. For example, in a server
application, the threads that handle
requests should catch Throwable
and relay any errors or exceptions
to the client. Another scenario is a
long-running thread that performs
some background activity. Such
threads should catch Throwable, log
any errors or exceptions, and then
continue functioning.
It is rarely good practice for a
method in a library to catch
Throwable. In general, errors and
exceptions should not be masked
from the caller.
This example demonstrates a long-
running thread that catches
Throwable and logs the exception.
class BgThread extends
Thread {
// Create a logger. For
more information on the logging
api's,
// see e385 The
Quintessential Logging Program
Logger logger =
Logger.getLogger("com.mycompany.
mypackage");

BgThread() {
// As a daemon
thread, this thread won't
prevent the application from
exiting
setDaemon(true);
}

// Set to true to shut


down this thread
boolean stop = false;

public void run() {


while (!stop) {
try {
// Perform
work here
} catch
(Throwable t) {
// Log the
exception and continue
logger.log(L
evel.SEVERE, "Unexception
exception", t);
}
}
}
}

Copying a Directory
// Copies all files under
srcDir to dstDir.
// If dstDir does not exist,
it will be created.
public void
copyDirectory(File srcDir, File
dstDir) throws IOException {
if
(srcDir.isDirectory()) {
if (!
dstDir.exists()) {
dstDir.mkdir();
}
String[] children =
srcDir.list();
for (int i=0;
i<children.length; i++) {
copyDirectory(ne
w File(srcDir, children[i]),

new File(dstDir, children[i]));


}
} else {
// This method is
implemented in e1071 Copying a
File
copyFile(srcDir,
dstDir);
}
}
GET and POST Requests
Question:
How does a servlet handle GET and
POST requests?
Answer:
The HttpServlet abstract class,
defined in the javax.servlet.http
package, contains several methods
that simplify interacting with HTTP
requests. Two of the methods take
care of handling GET and POST
requests. When you write a servlet,
you should subclass HttpServlet
and implement the doGet() method
to handle GET requests. Similarly,
to handle POST requests, you
would implement the doPost()
method.

Both methods take an


HttpServletRequest instance and
an HttpServletResponse instance
as arguments. The
HttpServletRequest instance
contains all the information
pertaining to the request, including
any request parameters. The
HttpServletResponse is used to
generate a response to the
request.
Lazy Versus Eager Instantiation
There are techniques for creation
of objects (read allocation of
memory) widely known as lazy
Instantiation and Eager
Instantiation.
Lazy instantiation is a memory
conservation technique, by which,
a program delays the creation of
objects until those objects are
needed. In Java, there are two
categories of lazy instantiation:
1. Lazy class loading
The Java runtime loads classes into
memory only when they're first
referenced. This may happen due
to a first call to a static method of
a class as in:
aClass.someStaticMethod();
or a first call to the "new" operator
to create an instatnce of a class as
in:
AClass aClass = new
AClass();
This is a very important feature of
the Java runtime. Memory usage
can be significantly reduced. For
example, if a part of a program is
never run, classes that are only
referenced by that part of the
program will never be loaded.
2. Lazy object creation
This is tightly coupled to lazy class
loading. It refers to when you
delay the creation of an instance of
a class until you really need it in
the code.
Eager Instantiation, on the other
hand, refers to technique that
instances of objects are created
before any part of the code actually
asks for them. This may
considerably improve runtime
performance since live objects are
sitting in runtime memory waiting
to be called. An example of eager
instantiation is creation of resource
pools, e.g. a pool of database
connections waiting for client calls.
Suppose you have to load images
on request based corresponding
image file names. You can write
code like:

public class AnImageFile


{
private String m_filename;
private Image m_image;
public AnImageFile(String
filename)
{
m_filename=filename;
//Now load the image in
constructor
}
public String getName()
{ m_return filename;}
public Image getImage()
{return m_image;}
}
This is an eager approach that
guarantees the availability of an
image right after creation of an
instance of AnImageFile class. This
will boost performance when a call
to getImage(...) is made. But if
you have many images, and create
AnImageFile instances of them,
you may use up a lot of memory
unnecessarily. You can trade
performance benefits to memory
uasage via lazy instantiation, as in:
public class ImageFile
{
private String m_filename;
private Image m_image=null;
public ImageFile(String
filename)
{
//Here we just store the
filename
m_filename=filename;
}
public String getName()
{ return m_filename;}
public Image getImage()
{
if(m_image==null)
{
//load the image
}
return m_image;
}
}
Here, the actual image is loaded
only on the first call to getImage().
So, you can reduce memory usage
and startup time by using lazy
instantiation and paying the price
for performance hit when you
create an object when it is actually
need. Or, you can increase the
startup time, and use up more
memory upfront to eagerly
instantiate objects in order to
boost performance.
Servlets vs. Applets
Question:
We currently use applets to allow
users to access a database, but are
looking for ways to improve
performance. Is a servlet-based
solution faster than an applet-
based solution?
Answer:
This will depend on the application,
the number of concurrent clients,
the average network latency and
bandwidth between a client and
the server, and other factors. In
general, if you want your
application to scale to large
numbers of users, you will want to
forego the applet-centric solution.
If each client applet has to create a
separate connection to the
database, transfer data, and
process it locally, you face several
potential bottlenecks.

First, you could overload your


database with too many
connections. Second, you may
have to transfer a lot of data over
the network, which may take a
long time. Third, the client may not
have enough processing power or
memory to process all of the data
in a timely manner, if at all. Other
problems also exist, such as the
inability to centralize business
logic, leading to software
maintenance difficulties.
The preferred design for such a
system is a three-tier architecture.
A three-tier system consists of a
client, a middle layer that performs
transaction processing, and a back-
end server. The client is usually
lightweight, only able to issue
queries and receive final results.
An example of this would be a
simple HTML form. The middle
layer's job is to mediate access to
server resources and possibly
perform processing on the client's
behalf. The server, of course,
stores the database or other
service that the client ultimately
wants to access. Additional data
processing can happen on the
server and extra tiers can be added
if multiple resources need to be
accessed.
Multi-tier architectures offer
several advantages. The primary
advantage is the ability to scale to
larger numbers of clients. The
transaction processing layer makes
this possible. It can keep a pool of
open connections to the server,
using them as appropriate to serve
client requests, saving the
overhead of opening a new
connection for every client. Rather
than overloading the server with
queries, the transaction processor
can throttle back the load on the
server by serializing requests. Data
processing can also be removed
from the client and pushed closer
to the data. The second major
advantage is the ability to cleanly
subdivide software development.
Each layer performs a well-
specified task that can be
developed without overly impacting
the other layers.
Making Better Use of Garbage
Collector
Imagine you have an enormous
object serialized on disk that you
are using in memory, or that object
is loaded in memory. You want to
allow the garbage collector (GC)
clean memory when it needs it,
right?. Imagine you are about to
run out of memory; do we really
need to wait until no reference is
made to our object?
Here´s a solution to allow the GC
to clean memory: It is based on
the Reference class placed into
java.lang.ref.* packet. Actually, it
is a subclass of Reference called
SoftReference. Here's how it
works:

Object myObj = new


myClass();---> legacy
reference , everyday ref.
Now comes the trick :
SoftReference sref = new
SoftReference(myObj);

At this point, we do have a soft


reference pointing to the object
and also a legacy ref pointing to
the same object. We MUST erase
this soft reference, because there
are between one and 1,000 refs
that could make this technique
unworlable:

myObj = null;
myObj = sref.get(); // we
recover the soft reference.
The get method should be
implemented to return the object,
or a null if it was placed to disk,
and we can do it as follows:

import java.land.ref.*;

We need an abstract to allow


subclasses implements methods:
public abstract class
SolutionBehaviour{
private SoftReference ref
= new SoftReference(null);
public Object get()throws
Exception{

This method implements the "get"


way of saying if all was right or
there was any kind of error:

Object obj = ref.get();


if (obj = null) {
// If null get the
object from disk
obj =
getFromStorage();
ref=new
SoftReference(obj);
}
return obj;
}
protected abstract Object
getFromStorage() throws
Exception;
}
Jose Antonio Alvarez Bermejo

Execute an External Program


Without Using JNI

The secret lies in the Runtime


class. Runtime contains the
method exec, which takes the basic
form of:
Process exec(String command) or
Process exec(String[] comdarray)
or
Process exec(String[] cmdarray,
String[] envp, File dir)

Where command is the name of


the executable, comdarray
contains the exe name and
arguments, envp contains the
environment variables, and File
contains the file name. exec
returns the abstract object Process,
whose getInputStream() and
getOutputStream() can be used to
collect I/O information on the
running process.
Determine Whether a User Session
Has Expired or Been Removed

Define a class, say


SessionTimeoutIndicator, which
implements the interface
javax.servlet.http.HttpSessionBindi
ngListener. Next create a
SessionTimeoutIndicator object
and add it to the user session.
When the session is removed, the
SessionTimeoutIndicator.valueUnb
ound() method will be called by the
Servlet engine. You can then
implement valueUnbound() to do
the required operation

Initializing Fields in Interfaces

Fields defined in interfaces are


automatically public, static, and
final. Being final, they cannot be
“blank”, but need to be initialized
with constant or non-constant
expressions. For example:
// Initializing interface fields
with non-constant expressions
import java.util.*;
public interface RandomValues {
int rint = (int)
(Math.random() * 10);
long rlong = (long)
(Math.random() * 10);
float rfloat = (float)
(Math.random() * 10);
double rdouble = Math.random()
* 10;
}

Since the fields are static, they are


initialized when the class is first
loaded. Here’s a simple test:
public class TestRandomValues {
public static void
main(String[] args) {
System.out.println(RandomVal
ues.rint);
System.out.println(RandomVal
ues.rlong);
System.out.println(RandomVal
ues.rfloat);
System.out.println(RandomVal
ues.rdouble);
}
}

Note: The fields, as expected, are


not part of the interface, but are
stored in the static storage area for
that interface.

Weaving Threads
Java provides two ways to create
and run a thread. You can
implement the Runnable interface
or extend the Thread class. The
Runnable interface defines a single
method run(). Consider the
following example of a class that
extends the Runnable interface:
1. Class RunnableClass
implements Runnable {
2. // Class attributes and
methods
3.
4. public void run() {
5. // Code for the run()
method
6. }
7. }
This thread can be started from
another section of the program as
follows:
8. RunnableClass rc = new
RunnableClass();
9. Thread t = new Thread(rc);
10. rc.start();
11. // Other code
The start() method calls the run()
method on Line 4. Program control
returns to Line 11 and
simultaneously to Line 5. At this
point two threads are executing.
The Thread class can also be
extended directly, making the
derived class a Runnable (Thread
extends Runnable):

1. public class ThreadClass


extends Thread {
2. public void run() {
3. // Code here
4. }
5. }
In this case, the thread may be
started directly with a single call:
6. ThreadClass tc = new
ThreadClass();
7. tc.start();
The Thread class has a lot more
overhead (in terms of methods and
attributes) and most of the time
the developers only need to use
the run() method. As a result,
implementing Runnable is the
preferred way to use threads.

Using Proxy Classes in Java


The Proxy is one of the most
common design patterns in
circulation. Gamma et. al. define
the intent of the Proxy as: "Provide
a surrogate or a placeholder for
another object to control access to
it." The basic idea is that a class
substitutes for another class. In
other words, a Proxy class provides
an interface that reflects the
interface of the class that it is
substituting. In Java, a Proxy class
must implement the same interface
as the class that it is substituting.
A Proxy is usually associated with a
client-server paradigm. The Server
and the Client classes implement
the same interface. However, the
Client only implements stubs of
methods where as the Server
provides the actual
implementations for the methods
specified in the interface. For
example:

1. public interface SomeIfc


{
2. public void aMethod();
3. }
4.
5. public class Client
implements SomeIfc {
6. Server s = new
Server();
7. // Other attributes
8.
9. public void aMethod ()
{
10. s.aMethod();
11. }
12.
13. // Other methods
14.
15. }
16.
17. public class Server
implements SomeIfc {
18.
19. // Class attributes
20. public aMethod () {
21. // Actual method
implementation.
22. }
23.
24. // Other methods
25. }
Lines 1-3 define an interface called
SomeIfc. It defines a single
method called aMethod(). Both the
Client class (Lines 5-15) as well as
the Server class (Lines 17-25)
implement the interface SomeIfc.
This ensures that aMethod() is
available to the application that
uses the Client class. On Line 6,
the Client instantiates a new object
of the type Server. In a real
application, the code on Line 6
would be replaced by code that
gets the Client a reference to the
Server across some transport
mechanism (like CORBA, sockets,
RMI, etc.).
Any call made to aMethod() on the
Client is "delegated" to the Server.
An application using the Client
class is shielded from the
knowledge that there is a Server in
the picture. The Client acts as a
Proxy to the Server. All access to
the Server is only available via the
Client.

You might also like