Collections.sort(stringList, String.
CASE_INSENSITIVE_ORDER);Singleton
public class OnlyOne {
private static OnlyOne one = new OnlyOne();
private OnlyOne(){… } //private constructor. This class cannot be instantiated from outside.
public static OnlyOne getInstance() {
return one;
}
}
- Accessing application specific properties through a singleton object, which reads them for the first time from a properties file and subsequent accesses are returned from in-memory objects. Also there could be another piece of code, which periodically synchronizes the in-memory properties when the values get modified in the underlying properties file. This piece of code accesses the in-memory objects through the singleton object (i.e. global point of access).
- Accessing in-memory object cache or object pool, or non-memory based resource pools like sockets, connections etc through a singleton object (i.e. global point of access).
Threads block on I/O
Note: The java.nio.* package was introduced in JDK1.4. The coolest addition is nonblocking I/O (aka NIO that stands for New I/O).
2 synchronized methods in one object
Thread communication
- The wait(), notify(), and notifyAll() methods are used to provide an efficient way for threads to communicate with each other. This communication solves the ‘consumer-producer problem’. This problem occurs when the producer thread is completing work that the other thread (consumer thread) will use.
wait and notify should be placed within synchronized code to ensure that the current code owns the monitor
- The notify method will wake up one thread waiting to reacquire the monitor for the object. You cannot be certain which thread gets woken. If you have only one waiting thread then you do not have a problem. If you have multiple waiting threads then it will probably the thread that has been waiting the longest that will wake up. However you cannot be certain, and the priorities of the threads will influence the result. As a result you are generally advised to use notifyAll instead of notify, and not to make assumptions about scheduling or priorities. Of course this is not always possible and you may have to try to test your code on as many platforms as possible.
daemon thread
synchronization level
- method: synchronize aMethod() {}
- statement: synchronize(anyObject) {}
- Often using a lock on a method level is too coarse. Why lock up a piece of code that does not access any shared resources by locking up an entire method. Since each object has a lock, dummy objects can be created to implement block level synchronization. The block level is more efficient because it does not lock the whole method.
thread, lock, monitor
- Entering the monitor building is called "entering the monitor."
- Entering the special room inside the building is called "acquiring the monitor."
- Occupying the room is called "owning the monitor,"
- and leaving the room is called "releasing the monitor."
- Leaving the entire building is called "exiting the monitor."
synchronized (anyObject) { }
.
yield vs sleep (thread)
Thread states
- Runnable — waiting for its turn to be picked for execution by the thread schedular based on thread priorities.
- Running: The processor is actively executing the thread code. It runs until it becomes blocked, or voluntarily gives up its turn with this static method Thread.yield(). Because of context switching overhead, yield() should not be used very frequently.
- Waiting: A thread is in a blocked state while it waits for some external processing such as file I/O to finish.
- Sleeping: Java threads are forcibly put to sleep (suspended) with this overloaded method: Thread.sleep(milliseconds), Thread.sleep(milliseconds, nanoseconds);
- Blocked on I/O: Will move to runnable after I/O condition like reading bytes of data etc changes.
- Blocked on synchronization: Will move to Runnable when a lock is acquired.
- Dead: The thread is finished working.
Creation of thread
- extends Thread. Thread t = new ExtendThread();
- implements Runnable. Thread t = new Thread(new ImplementRunnable());
Process/Thread
throw/throws
Best Practice for exception handling
- Catch subclass exception first.
- Throw an exception early
- Avoid suppressing or ignoring exceptions.
- Also avoid using exceptions just to get a flow control.
- Catch the exception at the appropriate layer
- Use checked exceptions when the client code can take some useful recovery action
- Use unchecked exception when client code cannot do anything based on information in exception.
Exception
PreparedStatement
Try-Catch-Finally
In the normal case, control reaches the end of the try block and then proceeds to the finally block, which performs any necessary cleanup. If control leaves the try block because of a return, continue, or break statement, the finally block is executed before control transfers to its new destination.
If an exception occurs in the try block, and there is an associated catch block to handle the exception, control transfers first to the catch block and then to the finally block. If there is no local catch block to handle the exception, control transfers first to the finally block, and then propagates up to the nearest containing catch clause that can handle the exception.
If a finally block itself transfers control with a return, continue, break, or throw statement or by calling a method that throws an exception, the pending control transfer is abandoned, and this new transfer is processed. For example, if a finally clause throws an exception, that exception replaces any exception that was in the process of being thrown. If a finally clause issues a return statement, the method returns normally, even if an exception has been thrown and has not been handled yet.
try and finally can be used together without exceptions or any catch clauses. In this case, the finally block is simply cleanup code that is guaranteed to be executed, regardless of any break, continue, or return statements within the try clause.
Joins: Innter, Outer,Equi, Natural..
<
disqualifies a join as equi-join. The query 2 sections above is already an example for equi-joins.garbage collector
- Each time an object is created in Java, it goes into the area of memory known as heap. The Java heap is called the garbage collectable heap. The garbage collection cannot be forced. The garbage collector runs in low memory situations. When it runs, it releases the memory allocated by an unreachable object. The garbage collector runs on a low priority daemon (background) thread. You can nicely ask the garbage collector to collect garbage by calling System.gc() but you can’t force it.
- What is an unreachable object? An object’s life has no meaning unless something has reference to it. If you can’t reach it then you can’t ask it to do anything. Then the object becomes unreachable and the garbage collector will figure it out. Java automatically collects all the unreachable objects periodically and releases the memory consumed by those unreachable objects to be used by the future reachable objects.
- We can use the following options with the Java command to enable tracing for garbage collection events. -verbose:gc reports on each garbage collection event.
type casting
- Type casting means treating a variable of one type as though it is another type.
- upcast = implicit, downcast = explicit
- When up casting primitives as shown below from left to right, automatic conversion occurs. But if you go from right to left, down casting or explicit casting is required. byte short int long float double
- When it comes to object references you can always cast from a subclass to a superclass because a subclass object is also a superclass object. You can cast an object implicitly to a super class type (i.e. upcasting). If this were not the case polymorphism wouldn’t be possible.
- You can cast down the hierarchy as well but you must explicitly write the cast and the object must be a legitimate instance of the class you are casting to. The ClassCastException is thrown to indicate that code has attempted to cast an object to a subclass of which it is not an instance. We can deal with the problem of incorrect casting in two ways: Use the exception handling mechanism to catch ClassCastException. Use the instanceof statement to guard against incorrect casting.
- Design pattern: The “instanceof” and “typecast” constructs are shown for the illustration purpose only. Using these constructs can be unmaintainable due to large if and elseif statements and can affect performance if used in frequently accessed methods or loops. Look at using visitor design pattern to avoid these constructs. (Refer Q11 in How would you go about section…).
- We can also get a ClassCastException when two different class loaders load the same class because they are treated as two different classes.
Nested Classes
Inner classes
re-entrant, recursive and idempotent
- A method in stack is re-entrant allowing multiple concurrent invocations that do not interfere with each other. To be reentrant, a function must hold no static data, must not return a pointer to static data, must work only on the data provided to it by the caller, and must not call non-reentrant functions. http://en.wikipedia.org/wiki/Reentrant
- A function is recursive if it calls itself. Given enough stack space, recursive method calls are perfectly valid in Java though it is tough to debug. Recursive functions are useful in removing iterations from many sorts of algorithms. All recursive functions are re-entrant but not all re-entrant functions are recursive.
- Idempotent methods are methods that repeated calls to the same method with the same arguments yield same results. For example clustered EJBs, which are written with idempotent methods, can automatically recover from a server failure as long as it can reach another server.
stack and heap memory
- There are two kinds of memory used in Java. These are called stack memory and heap memory. Stack memory stores primitive types and the addresses of objects. The object values are stored in heap memory.
- The primitive variables (local method variable) are allocated in the stack, but if they are member variables (i.e. fields of a class), they will be stored in the heap.
- In Java methods local variables are pushed into stack when a method is invoked and stack pointer is decremented when a method call is completed.
- In a multi-threaded application each thread will have its own stack but will share the same heap. The stack is threadsafe (each thread will have its own stack) but the heap is not threadsafe unless guarded with synchronisation through your code. This is why care should be taken in your code to avoid any concurrent access issues in the heap space.
final/finally/finalize()
- final - constant declaration. Refer Q27 in Java section.
- finally - handles exception. The finally block is optional and provides a mechanism to clean up regardless of what happens within the try block (except System.exit(0) call). Use the finally block to close files or to release other system resources like database connections, statements etc. (Refer Q45 in Enterprise section)
- finalize() - method helps in garbage collection. A method that is invoked before an object is discarded by the garbage collector, allowing it to clean up its state. Should not be used to release non-memory resources like file handles, sockets, database connections etc because Java has only a finite number of these resources and you do not know when the garbage collection is going to kick in to release these non-memory resources through the finalize() method.
final modifier
private constructor
Used in the singleton pattern. (Refer Q45 in Java section).
Used in the factory method pattern (Refer Q46 in Java section).
Used in utility classes e.g. StringUtils etc.
static method
Static/Instance Variable
Instance variables are non-static and there is one occurrence of an instance variable in each class instance (i.e. each object).
A static variable is used in the singleton pattern. (Refer Q45 in Java section). A static variable is used with a final modifier to define constants.
shallow/deep clone
Deep copy: If a deep copy is performed on an object then not only object has been copied but the objects contained within it have been copied as well. Serialization can be used to achieve deep cloning. Deep cloning through serialization is faster to develop and easier to maintain but carries a performance overhead.
all keys and values in the HashMap are Serializable. Its primary advantage is that it will deep copy any arbitrary object graph.
Improve IO performance
3. I/O performance can be improved by minimising the calls to the underlying operating systems. The Java runtime itself cannot know the length of a file, querying the file system for isDirectory(), isFile(), exists() etc must query the underlying operating system.
4. Where applicable caching can be used to improve performance by reading in all the lines of a file into a Java collection class like an ArrayList or a HashMap and subsequently access the data from an in-memory collection instead of the disk.
NIO
Design pattern: NIO uses a reactor design pattern, which demultiplexes events (separating single stream into multiple streams) and dispatches them to registered object handlers. The reactor pattern is similar to an observer pattern (aka publisher and subscriber design pattern), but an observer pattern handles only a single source of events (i.e. a single publisher with multiple subscribers) where a reactor pattern handles multiple event sources (i.e. multiple publishers with multiple subscribers). The intent of an observer pattern is to define a one-to-many dependency so that when one object (i.e. the publisher) changes its state, all its dependents (i.e. all its
subscribers) are notified and updated correspondingly. Another sought after functionality of NIO is its ability to map a file to memory. There is a specialized form of a
Buffer known as MappedByteBuffer, which represents a buffer of bytes mapped to a file. To map a file to MappedByteBuffer, you must first get a channel for a file. Once you get a channel then you map it to a buffer and subsequently you can access it like any other ByteBuffer. Once you map an input file to a CharBuffer, you can do
pattern matching on the file contents. This is similar to running “grep” on a UNIX file system. Another feature of NIO is its ability to lock and unlock files. Locks can be exclusive or shared and can be held on a contiguous portion of a file. But file locks are subject to the control of the underlying operating system.
Java IO stream
There are 2 kinds of streams.
- Byte streams (8 bit bytes) ?? Abstract classes are: InputStream and OutputStream
- Character streams (16 bit UNICODE) ?? Abstract classes are: Reader and Writer
Design pattern: java.io.* classes use the decorator design pattern. The decorator design pattern attaches responsibilities to objects at runtime. Decorators are more flexible than inheritance because the inheritance attaches responsibility to classes at compile time. The java.io.* classes use the decorator pattern to construct different combinations of behaviour at runtime based on some basic classes.
File file = new File(“c:/temp”);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
Serialization
Transient variables cannot be serialized. The fields marked transient in a serializable object will not be transmitted in the byte stream. An example would be a file handle or a database connection. Such objects are only meaningful locally. So they should be marked as transient in a serializable class.
- Depends on reflection.
- Has an incredibly verbose data format.
- Is very easy to send surplus data.
When to use serialization? Do not use serialization if you do not have to. A common use of serialization is to use it to send an object over the network or if the state of an object needs to be persisted to a flat file or a database. (Refer Q57 on Enterprise section). Deep cloning or copy can be achieved through serialization. This may be fast to code but will have performance implications (Refer Q22 in Java section).
pass-by-reference vs pass-by-value
http://jeeinterviews.com/typo/TIJ3/TIJ319.htm#Index2153
This brings up the terminology issue, which always seems good for an argument. The term is “pass by value,” and the meaning depends on how you perceive the operation of the program. The general meaning is that you get a local copy of whatever you’re passing, but the real question is how you think about what you’re passing. When it comes to the meaning of “pass by value,” there are two fairly distinct camps: Feedback
- Java passes everything by value. When you’re passing primitives into a method, you get a distinct copy of the primitive. When you’re passing a reference into a method, you get a copy of the reference. Ergo, everything is pass by value. Of course, the assumption is that you’re always thinking (and caring) that references are being passed, but it seems like the Java design has gone a long way toward allowing you to ignore (most of the time) that you’re working with a reference. That is, it seems to allow you to think of the reference as “the object,” since it implicitly dereferences it whenever you make a method call. Feedback
- Java passes primitives by value (no argument there), but objects are passed by reference. This is the world view that the reference is an alias for the object, so you don’t think about passing references, but instead say “I’m passing the object.” Since you don’t get a local copy of the object when you pass it into a method, objects are clearly not passed by value. There appears to be some support for this view within Sun, since at one time, one of the “reserved but not implemented” keywords was byvalue (This will probably never be implemented). Feedback
Having given both camps a good airing, and after saying “It depends on how you think of a reference,” I will attempt to sidestep the issue. In the end, it isn’t that important—what is important is that you understand that passing a reference allows the caller’s object to be changed unexpectedly.
http://jeeinterviews.com/scjp/source/10909/bbl0037.html
The bottom line on pass-by-value: the called method can't change the caller's variable, although for object reference variables, the called method can change the object the variable referred to. What's the difference between changing the variable and changing the object? For object references, it means the called method can't reassign the caller's original reference variable and make it refer to a different object, or null.
String vs StringBuffer/StringBuilder
StringBuffer is mutable: use StringBuffer or StringBuilder when you want to modify the contents. StringBuilder was added in Java 5 and it is identical in all respects to StringBuffer except that it is not synchronised, which make it slightly faster at the cost of not being thread-safe.
StringBuffer expands as needed, which is costly however, so it would be better to initilise the StringBuffer with the correct size from the start as shown.
Another important point is that creation of extra strings is not limited to ‘overloaded mathematical operators’ (“+”) but there are several methods like concat(), trim(), substring(), and replace() in String classes that generate new string instances. So use StringBuffer or StringBuilder for computation intensive operations, which offer better performance.
Methods to override for HashMap key
the equals() and hashcode(), which are inherited from the java.lang.Object uses an object instance’s memory
location (e.g. MyObject@6c60f2ea). This can cause problems when two instances of the car objects have the
same colour but the inherited equals() will return false because it uses the memory location, which is different for
the two instances. Also the toString() method can be overridden to provide a proper string representation of your
object. Points to consider:
• If a class overrides equals(), it must override hashCode().
• If 2 objects are equal, then their hashCode values must be equal as well.
• If a field is not used in equals(), then it must not be used in hashCode().
• If it is accessed often, hashCode() is a candidate for caching to enhance performance.
Initial Capacity & Load Factor
Hash table based implementation of the Map interface. This implementation provides all of the optional map operations, and permits null values and the null key. (The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.) This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
This implementation provides constant-time performance for the basic operations (get and put), assuming the hash function disperses the elements properly among the buckets. Iteration over collection views requires time proportional to the "capacity" of the HashMap instance (the number of buckets) plus its size (the number of key-value mappings). Thus, it's very important not to set the initial capacity too high (or the load factor too low) if iteration performance is important.
An instance of HashMap has two parameters that affect its performance: initial capacity and load factor. The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity at the time the hash table is created. The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased. When the number of entries in the hash table exceeds the product of the load factor and the current capacity, the capacity is roughly doubled by calling the rehash method.
As a general rule, the default load factor (.75) offers a good tradeoff between time and space costs. Higher values decrease the space overhead but increase the lookup cost (reflected in most of the operations of the HashMap class, including get and put). The expected number of entries in the map and its load factor should be taken into account when setting its initial capacity, so as to minimize the number of rehash operations. If the initial capacity is greater than the maximum number of entries divided by the load factor, no rehash operations will ever occur.
If many mappings are to be stored in a HashMap instance, creating it with a sufficiently large capacity will allow the mappings to be stored more efficiently than letting it perform automatic rehashing as needed to grow the table.
Note that this implementation is not synchronized. If multiple threads access this map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be "wrapped" using the Collections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map:
Map m = Collections.synchronizedMap(new HashMap(...));
The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
Best Practices for Collections
Collection Framework
Collections come in four basic flavors:
-
Lists Lists of things (classes that implement List).
-
Sets Unique things (classes that implement Set).
-
Maps Things with a unique ID (classes that implement Map).
-
Queues Things arranged by the order in which they are to be processed.
ArrayList, Vector, LinkedList
List Interface
A List cares about the index. The one thing that List has that non-lists don't have is a set of methods related to the index. Those key methods include things like get(int index), indexOf(Object o), add(int index, Object obj), and so on. All three List implementations are ordered by index position—a position that you determine either by setting an object at a specific index or by adding it without specifying position, in which case the object is added to the end. The three List implementations are described in the following sections.
ArrayList Think of this as a growable array. It gives you fast iteration and fast random access. To state the obvious: it is an ordered collection (by index), but not sorted. You might want to know that as of version 1.4, ArrayList now implements the new RandomAccess interface—a marker interface (meaning it has no methods) that says, "this list supports fast (generally constant time) random access." Choose this over a LinkedList when you need fast iteration but aren't as likely to be doing a lot of insertion and deletion.
Vector Vector is a holdover from the earliest days of Java; Vector and Hashtable were the two original collections, the rest were added with Java 2 versions 1.2 and 1.4. A Vector is basically the same as an ArrayList, but Vector methods are synchronized for thread safety. You'll normally want to use ArrayList instead of Vector because the synchronized methods add a performance hit you might not need. And if you do need thread safety, there are utility methods in class Collections (synchronizedList) that can help. Vector is the only class other than ArrayList to implement RandomAccess.
LinkedList A LinkedList is ordered by index position, like ArrayList, except that the elements are doubly-linked to one another. This linkage gives you new methods (beyond what you get from the List interface) for adding and removing from the beginning or end, which makes it an easy choice for implementing a stack or queue. Keep in mind that a LinkedList may iterate more slowly than an ArrayList, but it's a good choice when you need fast insertion and deletion. As of Java 5, the LinkedList class has been enhanced to implement the java.util.Queue interface. As such, it now supports the common queue methods: peek(), poll(), and offer().
l: scjp