Monday, November 7, 2011

Overriding Equals method and hashcode

Java allows users to override the equals method for custom comparison of objects. For example, if a scenario arises where the objects need to be compared at a level other than just the address. In such cases, the object needs to override the following methods:

1. public boolean equals(Object 0)
2. public int hashcode()

Both these methods have default implementation as part of the Object class which is inherited by all classes in java.

In the default implementation of equals method, a comparison is done on the memory address that the two objects point to. This means that only if the two variables point to the same object, the equals method will return true. However this is not always the desired mode of comparison. So Java allows developers to override this method for all classes.

In the default implementation of the hashcode method, the method returns the integer equivalent of memory location where the object is stored. There are 2 important rules that need to be taken care of while overriding the hashcode method.

1. The value of the hashcode cannot change once it is assigned. It needs to remain the same throughout the execution of the application. This is to ensure losing objects that are put in collection classes.

2. From a performance improvement perspective, 2 objects that are equal must have the same hashcode. Though the converse is not true - two objects with the same hashcode need not be equal.

Reason for overriding hashcode method when overriding equals method:

Consider the example of adding objects as keys to HashMap. While calling the put method of an HashMap with a key and value pair, a call is first made to the hashcode method of the key. This verifies if the object being added is a duplicate or not. If the key being added has the same hashcode as another object already present in the map, then the equals method is called to check for equality of the objects. If they do not have the same hashcode, then the key is immedaitely added to the map.

When we overwrite the equals method alone and leave the hashcode representation to be the default, there is a possibility that 2 equal objects(equal as defined by the custom method) will have different hashcodes. If we try to add 2 such objects to the map, we might end up creating duplicate entries in the map.

One possible way of overriding the hashcode method is to return a constant number for all objects. But this defeats the whole purpose of having a hashcode as everytime the hashcode is invoked to check for inquality, the map would goto the equals method to compare the objects(which is expensive).

It should also be noted that the hashcode can be made data dependant but however it needs to be taken care that it is assinged a value only once when the object is created and does not change everytime an object's data fields change. The reason can be explained with the example of adding two objects as keys in a HashMap. Consider an hashmap with two keys - obj1 with hashcode 10 and obj2 with hashcode 11. Now I modify the data in obj2 so that the data matches that of obj1 and the hashcode becomes 10. Now when I try to retrieve obj2 from the map, the map would return the value corresponding to key obj1. This leads to loss of data stored as part of obj2. Hence the value of hashcode needs to be assigned once and then everytime the hashcode method is invoked, this value needs to be retrieved rather than evaluating it again.

Friday, August 19, 2011

Cookies In and out

Source

http://www.quirksmode.org/js/cookies.html

Cookies

See section 6G of the book.

This script was originally written by Scott Andrew. Copied and edited by permission.

This article has been translated into French

On this page I give three functions to save, read and erase cookies. Using these functions you can manage cookies on your site.

First an introduction to cookies, and a summary of document.cookie, followed by an example. Then come the three functions and their explanation.

Cookies

Cookies were originally invented by Netscape to give 'memory' to web servers and browsers. The HTTP protocol, which arranges for the transfer of web pages to your browser and browser requests for pages to servers, is state-less, which means that once the server has sent a page to a browser requesting it, it doesn't remember a thing about it. So if you come to the same web page a second, third, hundredth or millionth time, the server once again considers it the very first time you ever came there.

This can be annoying in a number of ways. The server cannot remember if you identified yourself when you want to access protected pages, it cannot remember your user preferences, it cannot remember anything. As soon as personalization was invented, this became a major problem.

Cookies were invented to solve this problem. There are other ways to solve it, but cookies are easy to maintain and very versatile.

How cookies work

A cookie is nothing but a small text file that's stored in your browser. It contains some data:

  1. A name-value pair containing the actual data
  2. An expiry date after which it is no longer valid
  3. The domain and path of the server it should be sent to

As soon as you request a page from a server to which a cookie should be sent, the cookie is added to the HTTP header. Server side programs can then read out the information and decide that you have the right to view the page you requested or that you want your links to be yellow on a green background.

So every time you visit the site the cookie comes from, information about you is available. This is very nice sometimes, at other times it may somewhat endanger your privacy. Fortunately more and more browsers give you the opportunity to manage your cookies (deleting the one from the big ad site, for example).

Cookies can be read by JavaScript too. They're mostly used for storing user preferences.

name-value

Each cookie has a name-value pair that contains the actual information. The name of the cookie is for your benefit, you will search for this name when reading out the cookie information.

If you want to read out the cookie you search for the name and see what value is attached to it. Read out this value. Of course you yourself have to decide which value(s) the cookie can have and to write the scripts to deal with these value(s).

Expiry date

Each cookie has an expiry date after which it is trashed. If you don't specify the expiry date the cookie is trashed when you close the browser. This expiry date should be in UTC (Greenwich) time.

Domain and path

Each cookie also has a domain and a path. The domain tells the browser to which domain the cookie should be sent. If you don't specify it, it becomes the domain of the page that sets the cookie, in the case of this page www.quirksmode.org.
Please note that the purpose of the domain is to allow cookies to cross sub-domains. My cookie will not be read by search.quirksmode.org because its domain is www.quirksmode.org . When I set the domain to quirksmode.org, the search sub-domain may also read the cookie.
I cannot set the cookie domain to a domain I'm not in, I cannot make the domain www.microsoft.com . Only quirksmode.org is allowed, in this case.

The path gives you the chance to specify a directory where the cookie is active. So if you want the cookie to be only sent to pages in the directory cgi-bin, set the path to /cgi-bin. Usually the path is set to /, which means the cookie is valid throughout the entire domain.
This script does so, so the cookies you can set on this page will be sent to any page in the www.quirksmode.org domain (though only this page has a script that searches for the cookies and does something with them).

document.cookie

Cookies can be created, read and erased by JavaScript. They are accessible through the property document.cookie. Though you can treat document.cookie as if it's a string, it isn't really, and you have only access to the name-value pairs.

If I want to set a cookie for this domain with a name-value pair 'ppkcookie1=testcookie' that expires in seven days from the moment I write this sentence, I do

document.cookie =

'ppkcookie1=testcookie; expires=Thu, 2 Aug 2001 20:47:11 UTC; path=/'
  1. First the name-value pair ('ppkcookie1=testcookie')
  2. then a semicolon and a space
  3. then the expiry date in the correct format ('expires=Thu, 2 Aug 2001 20:47:11 UTC')
  4. again a semicolon and a space
  5. then the path (path=/)

This is a very strict syntax, don't change it! (Of course the script manages these dirty bits for you)

Also, even though it looks like I'm writing this whole string to the string document.cookie, as soon as I read it out again I only see the name-value pair:

ppkcookie1=testcookie

If I want to set another cookie, I again do

document.cookie =

'ppkcookie2=another test; expires=Fri, 3 Aug 2001 20:47:11 UTC; path=/'

The first cookie is not overwritten, as it would when document.cookie would be a real string. Instead the second one is added to document.cookie, so if we read it out we get

ppkcookie1=testcookie; ppkcookie2=another test

If I reset a cookie

document.cookie =

'ppkcookie2=yet another test; expires=Fri, 3 Aug 2001 20:47:11 UTC; path=/'

the old cookie is overwritten and document.cookie reads

ppkcookie1=testcookie; ppkcookie2=yet another test

To read out a cookie you have to treat document.cookie as a string and search for certain characters (semicolons, for instance) and for the cookie name. I'll explain how to do it below.

Finally, to remove a cookie, set it with an expiry date before today. The browser sees that the cookie has expired and removes it.

document.cookie =

'ppkcookie2=yet another test; expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/'

Example

If you're thoroughly confused by all this strange syntax, try the example below. You can set two cookies, ppkcookie1 and ppkcookie2. Fill in the desired value in the text box.

The value of the cookie should be

Create cookie 1
Read cookie 1
Erase cookie 1.

Create cookie 2
Read cookie 2
Erase cookie 2.

For comparision, read out document.cookie.

I set the cookies to remain active for seven days. If you return to this page within that time, you'll get an alert that the cookie(s) is/are still active. Try it by setting a cookie, then reloading this page.

The scripts

These are the three scripts you need.

function createCookie(name,value,days) {

if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}

function eraseCookie(name) {
createCookie(name,"",-1);
}

Explanation

The functions are not very difficult, the hardest part is creating the correct syntax for setting a cookie.

createCookie

When calling createCookie() you have to give it three bits of information: the name and value of the cookie and the number of days it is to remain active. In this case the name-value pair should become ppkcookie=testcookie and it should be active for 7 days.

createCookie('ppkcookie','testcookie',7)

If you set the number of days to 0 the cookie is trashed when the user closes the browser. If you set the days to a negative number the cookie is trashed immediately.

The function receives the arguments and starts doing its job.

function createCookie(name,value,days) {

First of all see if there is a days value. If there isn't we don't need to do the time calculation.

	if (days) {

If there is, create a new Date object containing the current date.

		var date = new Date();

Now get the current Time (in milliseconds) and add the required number of days (in milliseconds). Set the Time of the date to this new value, so that it now contains the date in milliseconds that the cookie should expire.

		date.setTime(date.getTime()+(days*24*60*60*1000));

Set the variable expires to this date in the UTC/GMT format required by cookies.

		var expires = "; expires="+date.toGMTString();

}

If 0 is passed to the function, expires is not set and the cookie expires when the user closes his browser..

	else var expires = "";

Finally write the new cookie into document.cookie in the correct syntax.

	document.cookie = name+"="+value+expires+"; path=/";

}

Cookie created.

readCookie

To read out a cookie, call this function and pass the name of the cookie. Put the name in a variable. First check if this variable has a value (if the cookie does not exist the variable becomes null, which might upset the rest of your function), then do whatever is necessary.

var x = readCookie('ppkcookie1')

if (x) {
[do something with x]
}

The function receives the argument and starts.

function readCookie(name) {

We're going to search for the name of the cookie, followed by an =. So create this new string and put it in nameEQ:

	var nameEQ = name + "=";

Then split document.cookie on semicolons. ca becomes an array containing all cookies that are set for this domain and path.

	var ca = document.cookie.split(';');

Then we go through the array (so through all cookies):

	for(var i=0;i < ca.length;i++) {

Set c to the cookie to be checked.

		var c = ca[i];

If the first character is a space, remove it by using the substring() method. Continue doing this until the first character is not a space.

		while (c.charAt(0)==' ') c = c.substring(1,c.length);

Now string c begins with the name of the current cookie. If this is the name of the desired cookie

		if (c.indexOf(nameEQ) == 0)

we've found what we were looking for. We now only need to return the value of the cookie, which is the part of c that comes after nameEQ. By returning this value we also end the function: mission accomplished.

		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);

}

If, after having gone through all cookies, we haven't found the name we're looking for, the cookie is not present. We return null.

	return null;

}

Cookie read.

eraseCookie

Erasing is extremely simple.

eraseCookie('ppkcookie')

Pass the name of the cookie to be erased

function eraseCookie(name) {

and call createCookie() to set the cookie with an expiry date of one day ago.

	createCookie(name,"",-1);

}

The browser, seeing that the expiry date has passed, immediately removes the cookie.

Tuesday, July 12, 2011

Collections




  • Collection — the root of the collection hierarchy. A collection represents a group of objects known as its elements. The Collection interface is the least common denominator that all collections implement and is used to pass collections around and to manipulate them when maximum generality is desired. Some types of collections allow duplicate elements, and others do not. Some are ordered and others are unordered. The Java platform doesn't provide any direct implementations of this interface but provides implementations of more specific subinterfaces, such as Set and List. Also see The Collection Interface section.

  • Set — a collection that cannot contain duplicate elements. This interface models the mathematical set abstraction and is used to represent sets, such as the cards comprising a poker hand, the courses making up a student's schedule, or the processes running on a machine. See also The Set Interface section.

  • List — an ordered collection (sometimes called a sequence). Lists can contain duplicate elements. The user of a List generally has precise control over where in the list each element is inserted and can access elements by their integer index (position). If you've used Vector, you're familiar with the general flavor of List. Also see The List Interface section.

  • Queue — a collection used to hold multiple elements prior to processing. Besides basic Collection operations, a Queue provides additional insertion, extraction, and inspection operations.

    Queues typically, but do not necessarily, order elements in a FIFO (first-in, first-out) manner. Among the exceptions are priority queues, which order elements according to a supplied comparator or the elements' natural ordering. Whatever the ordering used, the head of the queue is the element that would be removed by a call to remove or poll. In a FIFO queue, all new elements are inserted at the tail of the queue. Other kinds of queues may use different placement rules. Every Queue implementation must specify its ordering properties. Also see The Queue Interface section.

  • Map — an object that maps keys to values. A Map cannot contain duplicate keys; each key can map to at most one value. If you've used Hashtable, you're already familiar with the basics of Map. Also see The Map Interface section.
The last two core collection interfaces are merely sorted versions of Set and Map:
  • SortedSet — a Set that maintains its elements in ascending order. Several additional operations are provided to take advantage of the ordering. Sorted sets are used for naturally ordered sets, such as word lists and membership rolls. Also see The SortedSet Interface section.

  • SortedMap — a Map that maintains its mappings in ascending key order. This is the Map analog of SortedSet. Sorted maps are used for naturally ordered collections of key/value pairs, such as dictionaries and telephone directories. Also see The SortedMap Interface section.

Tuesday, June 21, 2011

InputStreams & Output Streams



Prior to JDK 1.1, the input and output classes (mostly found in the java.io package) only supported 8-bit byte streams. The concept of 16-bit Unicode character streams was introduced in JDK 1.1. While byte streams were supported via the java.io.InputStream and java.io.OutputStream classes and their subclasses, character streams are implemented by the java.io.Reader and java.io.Writer classes and their subclasses.


Methods defined in InputStream :


available() – bytes of input available for reading will be returned by this method.
close() – closes the input source.IOException will be generated if further reading continues.
mark(int numberofBytes) – Responsible to put a mark at the current point in the input stream .Validity will be
until you read those number of bytes
markSupported() – returns Boolean value true if this feature of mark()/reset() is supported.
read() –next available bytes integer representation in the input returned by this method .
reset() – For resetting the input pointer to previous set mark.
skip(long numberofBytes) – ignores the numberofBytes of input and returns the numberofBytes ignored
actually.


ByteArrayInputStream
Example :


byte b[] = tmp.getBytes();
ByteArrayInputStream in = new ByteArrayInputStream(b);

while ((c = in.read()) != -1) {
System.out.print(Character.toUpperCase((char) c));
}

FileInputStream:
File file = new File("DevFile.txt");

int ch;
StringBuffer strContent = new StringBuffer("");
FileInputStream fin = null;

try {
fin
= new FileInputStream(file);

while ((ch = fin.read()) != -1)
strContent
.append((char) ch);

fin
.close();
ObjectInputStream :
The ObjectInputStream class enables you to read Java objects from InputStream's instead of only bytes. You wrap an InputStream in a ObjectInputStream and then you can read objects from it. Here is an example:

ObjectInputStream input = new ObjectInputStream(
new FileInputStream("object.data"));

MyClass object = (MyClass) input.readObject();
//etc.

input.close();
BufferedInputStream

A BufferedInputStream wrapped around a FileInputStream, though, will request data from the FileInputStream in big chunks (512 bytes or so by default, I think.) Thus if you read 1000 characters one at a time, the FileInputStream will only have to go to the disk twice. This will be much faster!
  1. FileInputStream fis = new FileInputStream("MyFile.dat");
  2. BufferedInputStream bis = new BufferedInputStream(fis);
  3. int c;
  4. while ((c = bis.read) != -1) {
  5. // Do something with the single byte in "c";
  6. }
  7. bis.close(); // "fis" gets closed automatically
Missing, unflushed output to System.out is a common newbie problem. You can use a shutdown hook (see Runtime.addShutdownHook()) to ensure data will be flushed; an industrial-strength logging package should definitely do so.

DataInputStream :

it also implements DataInput, interface.
A data input stream lets an application read primitive Java data types from an underlying input stream in a machine-independent way. An application uses a data output stream to write data that can later be read by a data input stream.




double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 };
int[] units = { 12, 8, 13, 29, 50 };
String[] descs = { "Java T-shirt", "Java Mug", "Duke Juggling Dolls", "Java Pin", "Java Key Chain" };

DataOutputStream dos = new DataOutputStream(
new FileOutputStream("c:/invoice1.txt"));
for (int i = 0; i < prices.length; i ++) {
dos.writeDouble(prices[i]);
dos.writeChar('\t');
dos.writeInt(units[i]);
dos.writeChar('\t');
dos.writeChars(descs[i]);
dos.writeChar('\n');
}
dos.close();

DataInputStream dis = new DataInputStream(new FileInputStream("c:/invoice1.txt"));

double price;
int unit;
String desc;
double total = 0.0;

try {
while (true) {
price = dis.readDouble();
dis.readChar(); // throws out the tab
unit = dis.readInt();
dis.readChar(); // throws out the tab
desc = dis.readLine();
System.out.println("You've ordered " + unit + " units of " + desc + " at $" + price);
total = total + unit * price;
}
} catch (EOFException e) {
}

PushbackInputStream :


A PushbackInputStream adds functionality to another input stream, namely the ability to "push back" or "unread" one byte. This is useful in situations where it is convenient for a fragment of code to read an indefinite number of data bytes that are delimited by a particular byte value; after reading the terminating byte, the code fragment can "unread" it, so that the next read operation on the input stream will reread the byte that was pushed back. For example, bytes representing the characters constituting an identifier might be terminated by a byte representing an operator character; a method whose job is to read just an identifier can read until it sees the operator and then push the operator back to be re-read.

class PushbackInputStreamDemo {
public static void main(String args[]) throws IOException {
String s = "if (a == 4) a = 0;\\n";
byte buf[] = s.getBytes();
ByteArrayInputStream in = new ByteArrayInputStream(buf);
PushbackInputStream f = new PushbackInputStream(in);
int c;
while ((c = f.read()) != -1) {
switch(c) {
case '=':
if ((c = f.read()) == '=')
System.out.print(".eq.");
else {
System.out.print("<-");
f.unread(c);
}
break;
default:
System.out.print((char) c);
break;
}
}
}
}


OutputStreams :

Methods defined in OutputStream are,

close() – This closes the output stream.
flush() – It flushes the output buffers.
write(int b) – this writes a byte to an output stream
write(byte buffer[]) - this writes an array of bytes to the output stream
write(byte buffer[], int offset, int numberofBytes) this writes a specified range of bytes from a
byte array to the output stream



PrintStream :

A PrintStream adds functionality to another output stream, namely the ability to print representations of various data values conveniently. Two other features are provided as well. Unlike other output streams, a PrintStream never throws an IOException; instead, exceptional situations merely set an internal flag that can be tested via the checkError method. Optionally, a PrintStream can be created so as to flush automatically; this means that the flush method is automatically invoked after a byte array is written, one of the println methods is invoked, or a newline character or byte ('\n') is written.

All characters printed by a PrintStream are converted into bytes using the platform's default character encoding. The PrintWriter class should be used in situations that require writing characters rather than bytes.


FileOutputStream out;
PrintStream ps; // declare a print stream object
try {
// Create a new file output stream
out = new FileOutputStream("myfile.txt");

// Connect print stream to the output stream
ps = new PrintStream(out);

ps.println ("This data is written to a file:");
System.err.println ("Write successfully");
ps.close();




Sources & Sinks:

Java 1.0 class

Corresponding Java 1.1 class
InputStream
Reader

converter: InputStreamReader

OutputStream
Writer

converter: OutputStreamWriter

FileInputStream
FileReader
FileOutputStream
FileWriter
StringBufferInputStream
StringReader
(no corresponding class)
StringWriter
ByteArrayInputStream
CharArrayReader
ByteArrayOutputStream
CharArrayWriter
PipedInputStream
PipedReader
PipedOutputStream
PipedWriter



Differences :

The main difference between BufferedReader and BufferedInputStream is that Reader's work on characters (text), wheres InputStream's works on raw bytes.


Arrays

  • arrays are Java objects
  • all Java arrays are technically one-dimensional. Two-dimensional arrays are arrays of arrays.
  • declaring an array does not create an array object or allocate space in memory; it creates a variable with a reference to an array
  • array variable declarations must indicate a dimension by using [] 

 // declares an array of integers
        int[] anArray;

        // allocates memory for 10 integers
        anArray = new int[10];
 
 
Accessing Arrays 
 
         int arrval[]= new int[10];
  ArrayList<Object> arrList= new ArrayList();
  
  for (int a: arrval) {
   
   
  }
  for (Object obj : arrList) {
   
  } 

Monday, March 28, 2011

Variables

Data Type Description Size Default Value
boolean true or false 1-bit false
char Unicode Character 16-bit \u0000
byte Signed Integer 8-bit (byte) 0
short Signed Integer 16-bit (short) 0
int Signed Integer 32-bit 0
long Signed Integer 64-bit 0L
float Real number 32-bit 0.0f
double Real number 64-bit 0.0d

  1. Declaring an uninitialised variable at class level is valid and it takes a default value of 0 or null
  2. Declaring an uninitialised local variable and referencing/using it is allowed (compilation error - variable is not initialized)
Representing different number system :

     int decVal = 26;     // The number 26, in decimal
int octVal = 032; // The number 26, in octal
int hexVal = 0x1a; // The number 26, in hexadecimal
int binVal = 0b11010; // The number 26, in binary

Representing float
:

double d1 = 123.4;
double d2 = 1.234e2; // same value as d1, but in scientific notation


Underscore
:

The following example shows other ways you can use the underscore in numeric literals:

long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi = 3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;

You can place underscores only between digits; you cannot place underscores in the following places:

* At the beginning or end of a number
* Adjacent to a decimal point in a floating point literal
* Prior to an F or L suffix
* In positions where a string of digits is expected

The following examples demonstrate valid and invalid underscore placements in numeric literals:

float pi1 = 3_.1415F; // Invalid; cannot put underscores adjacent to a decimal point
float pi2 = 3._1415F; // Invalid; cannot put underscores adjacent to a decimal point
long socialSecurityNumber1
= 999_99_9999_L; // Invalid; cannot put underscores prior to an L suffix

int x1 = _52; // This is an identifier, not a numeric literal
int x2 = 5_2; // OK (decimal literal)
int x3 = 52_; // Invalid; cannot put underscores at the end of a literal
int x4 = 5_______2; // OK (decimal literal)

int x5 = 0_x52; // Invalid; cannot put underscores in the 0x radix prefix
int x6 = 0x_52; // Invalid; cannot put underscores at the beginning of a number
int x7 = 0x5_2; // OK (hexadecimal literal)
int x8 = 0x52_; // Invalid; cannot put underscores at the end of a number

int x9 = 0_52; // OK (octal literal)
int x10 = 05_2; // OK (octal literal)
int x11 = 052_; // Invalid; cannot put underscores at the end of a number