JavaRanch Newsletter Articles in this issue :
Storing Objects in Java 4 - The Collections classThomas Paul Printable Version
Cindy's Segment - a Whimsical View of the WorldCindy Glass Printable Version
Assertions - Debugging in J2SE 1.4Thomas Paul Printable Version
Sun Certified Java Programmers Exam for JDK 1.4Marcus Green Printable Version
An Introduction to java.util.regex - Lesson 1 Dirk Schreckmann Printable Version
Java and C# - A Programmer's ComparisonThomas Paul Printable Version
Cattle Drive Update Dirk Schreckmann Printable Version
Book Review of the MonthCindy Glass
Madhav Lakkapragada
Printable Version
September GiveawaysCarl Trusiak Printable Version
September NewsCarl Trusiak Printable Version

Storing Objects in Java
Part 4 - The Collections class

by Thomas Paul

In this last column in our series, we are going to look at an important class to support the use of Collections and Maps. The Collections class contains static methods designed to assist you in your use of your Collection objects. The class itself has a private constructor, so it can't be instantiated or extended. All the methods of the class are static. What kinds of methods are included? Let's take a look.

Sorting

The Collections class contains two methods you can use to sort a List. As we discussed in Part 2 of this series, sorting can be done by having all the Objects to be sorted implement the compareTo( ) method or by passing in a Comparator object to control sorting. The sort actually works by extracting an array from the List and then running the Arrays.sort( ) method.

Here are the two sort methods:

  • void sort(List list) - Sorts the List using the compareTo( ) method of the objects in the List.
  • void sort(List list, Comparator comparator) - Sorts the List using the specified comparator.

Searching

Once you have sorted your List, you can run a binary search against it when you need to locate an item in the List. This will be much more efficient than iterating through the List to find an entry. The results are undefined if you use a binary search on a List that is not sorted. The binarySearch( ) methods will return the index of the found entry. If it isn't found, the methods will return a negative number which if made positive would represent where in the List this item should be inserted to maintain sort order.

Here are the two sort methods:

  • int binarySearch(List list, Object key) - Searches the List for the specified key using a binary search algorithm. The compareTo( ) method is used.
  • int binarySearch(List list, Object key, Comparator comparator) - Searches the List for the specified key using a binary search algorithm. The comparator is used.

If you need to find that max or min elements in a Collection, there are methods for that also. The Collection doesn't need to be sorted to run these methods.

Here are the max/min methods:

  • Object max(Collection coll)
  • Object max(Collection coll, Comparator comp)
  • Object min(Collection coll)
  • Object min(Collection coll, Comparator comp)

Synchronization

All of the Collection objects can be made thread-safe by using one of the synchronization methods. Two things should be noted:

  1. All operations against the Collection or Map must be done through the returned synchronized object and not the object passed into the synchronization method.
  2. Although all operations against the synchronized object are thread-safe, operations against the iterator of these objects are not. When iterating over the Collection or Map, you must synchronize the block of code on the synchronized object. Here is an example:
      Collection c = Collections.synchronizedCollection(collection);
         ...
      synchronized(c) {
          Iterator i = c.iterator(); 
          while (i.hasNext())
             processEntry(i.next());
      }

Here are the synchronization methods:

  • Collection synchronizedCollection(Collection c)
  • List synchronizedList(List l)
  • Map synchronizedMap(Map m)
  • Set synchronizedSet(Set s)
  • Sortedmap synchronizedSortedMap(SortedMap s)
  • SortedSet synchronizedSortedSet(SortedSet s)


Creating Unmodifiable Collections

There may be times when you want to pass a Collection or Map to another class but you want to insure that the object you pass is not changed. You can do this by passing an unmodifiable Collection or Map. The Collections class provides methods to create an unmodifiable view of a Collection or Map. This view is not a copy of the original object but simply passes through all methods that don't change the contents of the object. All other methods will throw an UnsupportedMethodException. This limitation is true for the object itself, any iterators created from the object, as well as any Collections created (in the case of a Map).

Here are the methods to create unmodifiable objects:

  • Collection unmodifiableCollection(Collection c)
  • List unmodifiableList(List l)
  • Map unmodifiableMap(Map m)
  • Set unmodifiableSet(Set s)
  • SortedMap unmodifiableSortedMap(SortedMap s)
  • SortedSet unmodifiableSortedSet(SortedSet s)


Creating Singleton Collections

There may be times when you want to pass a single object to a method that requires a Collection as an input parameter. You can do this by creating a singleton Collection. The singleton methods construct a Collection or Map out of the Object parameters that you pass to the method.

Here are the singleton methods:

  • Collection singleton(Object o)
  • List singeltonList(Object o)
  • Map singletonMap(Object key, Object value)

Other Odds and Ends

The Collections class has several other methods which may be useful under certain circumstances. Need to randomize the items in your list? Try one of the shuffle( ) methods. Or you can reverse the order of your List with the reverse( ) method or rotate items within the List using the rotate( ) method. Or you can use the enumeration( ) method to create an Enumeration from your Collection. Or use the list( ) method to create an ArrayList from your Enumeration. Need to fill a List with the same Object? There's the fill( ) method. Need to create a List containing the same Object n times? Try the nCopies( ) method. You can replace one Object in a List with another Object using replaceAll( ) or swap the position of two Objects in a List using the swap( ) method.

One last property of the Collections class is sometimes useful. Do you need to pass an empty List, Map, or Set to a method? Don't bother creating one. As long as the method won't attempt to modify the Object, you can use Collections.EMPTY_LIST, Collections.EMPTY_MAP, or Collections.EMPTY_SET.

Conclusion

The Collections class contains some useful (and some unusual) methods to help us work with Collection and Map objects. If you ever need any of the functionality it provides, the Collections class can save you some trouble and speed up your development.

That is the end of our four part series on Collections and Maps. I hope you found the information in this series useful.


Return to Top

Cindy's Segment - a Whimsical View of the World

Segment 7:
Asserting Yourself in Public
Or -
Testing Your Skills

Bill Bixby - the Magician

Ladies and Gentlemen!! Come One! Come All! Welcome to the most Amazing show in all JavaLand!

Presenting the one and only Master Coder ready to Razzle you! Ready to Dazzle you! Ready to Astound you with his feats of skill and daring. Ready to AMAZE you with magic such as has NEVER been seen before in all JavaLand!!

Come right on in!

ClassFile Castle

The Magnificent Assertion Show

Step right up and let me tell you about Assertions. How they can do your work for you. How they can cure everything from flow headaches to achy interfaces. All you need to know is the secret. And the secret is . . . that the new keyword Assert translates to "Make Sure".

What every Master Coder knows is that Asserts are like marking the deck. You put these little magical markers in your code and suddenly you know where all the cards and all the problems are.

Did you know that there are TWO- count them TWO- syntax forms for Assertions? The simple and easy form Assert ThisIsTrue (read this "Make Sure this is True") which spits a simple AssertionError if not true, and the more dramatic, Assert ThisIsTrue : DramaticExplanation which explodes with an AssertionError containing your Dramatic Explanation if not true!! .

Of course like all magic, Assertions have a price, and therefore you need to KNOW how to control them, KNOW how to make them work for you, KNOW how to make them disappear on command! But you, too, can learn this magic and amaze your co-workers and your boss!

Now you see them - Now you don't!

OK now - the first bit of magic is learning the "-source 1.4" command. If you want to do this magic you MUST compile using these mystical words. Otherwise the power will not be invoked! This keeps lesser mortals and compilers from being stunned by the power within.

The next bit of magic is remembering that Assertions cause an Error - not an Exception. This is to keep true IDIOTS from trying to recover when an Assert sends its magical message. One trick at a time please. End the program already, and start it again to see a different trick.

Now - time for the show. No matter how many bits of magic you sprinkle over your code, even if you compile it with the magic words - your Asserts are invisible until you wave your magic wand. Not just invisible - they REALLY do not cause ANY impact to ANYTHING - performance, CPU ANYTHING! They are TRANSPARENT to the JVM!!

Your wand is composed of combinations of -ea and -da, -esa and -dsa parameters when you start your application. (EnableAssertions, DisableAssertions, EnableSystemAssertions, DisableSystemAssertions). You can combine them at different power limitations - className, packageName or no limit levels. Your imagination is your boundary!

  • java -ea MyApp (turns ALL your classes on).
  • java -ea:com.magic.SomePackage MyApp (turns just the SomePackage on).
  • java -ea:com.magic.SomePackage -da:com.magic.sillyClass MyApp (turns just the SomePackage on - except the named class)
  • java -esa MyApp (turns just System Classes on)
  • java -ea - esa MyApp (turns EVERYTHING on)
  • And the beauty of it all is that - to make all those Asserts just DISAPPEAR - all you have to do is . . . nothing. Just call your app with none of these parameters and POOF!! the Asserts have disappeared.

    Test your Feats of Skill and Daring!

    How do you make Assertions work for you?

    The first trick is to locate all the places in your code where you KNOW something is true.

  • The last statement in a nested If series where you know everything else MUST meet . . . some conditions. Put "Assert ThisConditionStatement" there and as long as it IS TRUE - no problem, but as soon it is NOT TRUE your program throws an error.
  • A switch statement where you KNOW that one of the options will always work - therefore the default clause should NEVER get fallen into - put "Assert false : WhatValueFellInHere" in that default clause and you will KNOW if it somehow happens. Note: Did you READ that correctly? That should read "Make sure 'this is false' is a true statement".
  • Any place that "is reachable" but could should never be reached because of your fantastic logic - put "Assert false"
  • The second trick is remember these rules of Magic:

  • Never trust a method to begin clean
  • Never trust a method to end clean
  • Never trust an instance to be clean
  • When your method begins - you KNOW what the input parameters should be - after all you coded all the calls (at least the non-public ones). Make sure that you did them correctly with an Assert. A little secret here though - if it is a PUBLIC method - you should not use Asserts to check that some outsider sent a correct parameter. Blast them with a REAL Exception!!

    When your method is ending - you KNOW the things that should be true at that point. Just before you return a value - Make Sure that you are returning the correct value with an Assert.

    When you modify an instance - you KNOW the things that should be true always about it. When you publically construct an instance - check that your instance still makes sense. When you publically modify your instance - check that instance again.

    Warning: This is for professionals only! Do not try this at home! (with your less that 1.4 JDK).

    Magic Lessons - what NOT to do.

    We already talked about not using magic Asserts to check that public methods are sending the proper things. When amateurs and the general public call a method poorly, they NEED to ALWAYS get real Exception - not an Assert.

    Be Careful to not shoot yourself in the foot with your own wand! Make sure that you do not create the power to make transparent something that your program always needs.

    When you sprinkle your magic through your code - take care that you do not cause any side effects to your code. You might diminish the wonder of the other Asserts that you have added.

    Well - unless of course the only side effects are things that relate to other Asserts that you WANT to happen to help the other Asserts.

    Be Aware that for the very FEW, there are powerful ClassLoader methods out there that can increase your powers.

    If you are Brave and Talented you can gain the powers of:

  • public void setClassAssertionStatus (String className, boolean enabled)
  • public void setDefaultAssertionStatus(boolean enabled)
  • public void setPackageAssertionStatus(String packageName, boolean enabled)
  • public void clearAssertionStatus()
  • They can manipulate the contents of the 3 magic enabling fields:

  • private boolean defaultAssertionStatus = false;
  • private Map packageDefaultAssertionStatus = new HashMap();
  • private Map classAssertionStatus = new HashMap();
  • Study the use of these well, and you will be a Master among Masters!!

    ____________

    Now take this new found knowledge - and use it wisely and well. And may the magic lead you to the error of your ways and guide you to the inner truths!

    Copyright ? 2002. Cindy Glass. All rights reserved.


    Graphics by Pauline McNamara and Stephanie Grasson

    Next month - "Abnormal Psychology"- or - "Volitile and Transient Moods"

    ?

    ?


    Return to Top

    Assertions - Debugging in J2SE 1.4

    by Thomas Paul

    Introduction

    Assertions are new to Java and are included in the SCJP 1.4 exam. Anyone planning to take the exam should understand the concepts behind the assert keyword. In fact, all Java developers should understand assertions so they can determine if using them can be helpful in their development projects.

    In order to make assertions work, a new keyword, assert, has been added to Java. This means that a class written using assertions can not be compiled using older versions of J2SE. It also means that classes compiled with the assert keyword can not be run in earlier versions of the JRE.

    What is the purpose of the assert keyword? The purpose of assertions is to test your assumptions about the state of your program during execution. For example, if variable employee should never be null, you can test this assumption and stop your program if it occurs. Assertions are designed to be a development aid. You should not use assertions with the idea of testing conditions during production runs. Your class may be executed with assertions turned off so that if your program relies on assertions to run correctly then it may fail.

    The Basics

    The simple format of the assert statement is:

         assert BooleanExpression;

    The BooleanExpression is any expression that returns either a true or false. Assuming that we are running with assertions turned on, Java will terminate with an AssertionError if this statement returns a false.

    The second format of the assert statement is:

         assert BooleanExpression: ValueExpression;

    The ValueExpression can be any expression that returns a value. The value (normally a String) will be added to the error message returned when the assertion fails.

    Let's look at a very simple program using an assertion.

    public class AssertTest
    {
    	public static void main(String[] args)
    	{
    		assert false: "This class always fails";
    	}
    }

    This program will always terminate with an AssertionError if assertions are turned on. To compile this program we need to add a parameter (-source) to the compile statement. If we don't add the -source, use of the assert keyword will generate a compile error:

    AssertTest.java:5: warning: as of release 1.4, assert is a keyword, and may not be used as an identifier

    Here's the javac command to compile our assertion test class:

         javac -source 1.4 AssertTest.java

    After successfully compiling, if you want to execute your program with assertions turned on then you must us the -enableassertions (or -ea) switch. To execute our assertion test program we would do the following:

         java -ea AssertTest

    This will give us this result:

    java.lang.AssertionError: This class always fails
    	at AssertTest.main(AssertTest.java:5)
    Exception in thread "main" 

    Using Assertions

    So why do we use assertions? The purpose of an assertion is to test to see if something that should never happen happens! So if we calculate a value and that value should only contain an even number, we can test that assertion and throw an AssertionError if the test fails. For example:

    public class AssertTest
    {
    	public static void main(String[] args)
    	{
    		int retValue = getEvenNumber(Integer.parseInt(args[0]));
    		assert retValue % 2 == 0;
    	}
    
    	public static int getEvenNumber(int number) 
        {
    		return number * 3;
    	}
    }

    The result of running this class will depend on the input. At times it will run normally and other times it will throw an AssertionError. This gives you an opportunity to test your assumption (the getEvenNumber method always returns an even number) without having to write if...else logic and having to remove the code for production. It also helps to document your assumptions as the next person to work on this class will see that you are asserting that the getEvenNumber method always returns an even number.

    However, you do not want to code your programs as if assertions are always turned on. Remember, assertions must be specifically activated at runtime or they will not be executed. As an example, the following code may look like a good way to validate input to your method but it should be avoided.

    public class AssertTest
    {
    	public static void main(String[] args)
    	{
    		processEvenNumber(Integer.parseInt(args[0]));
    	}
    
    	public static void processEvenNumber(int number)
    	{
    		assert number % 2 == 0;
    		// process the input
    		return;
    	}
    }

    If the class is executed without assertions being turned on, the validation will not occur. Instead of using assertions for this case, you should use normal if...else constructs. You should use assertions (1) during development and (2) while in production to debug production problems. Testing such as the example above where we are verifying the input prior to executing the method's logic is called precondition verification. Never use assertions for precondition verification unless it is in a private method where you control the input. In that case, you can verify that your code is giving the correct input to your method.

    Assertions can be used for postcodition verification in private or public methods. Postcondition verification is where we test the output of our method to insure that the result we are returning is correct. An example of postcondition verification:

    public class AssertTest
    {
    	public static void main(String[] args)
    	{
    		int retValue = getEvenNumber(Integer.parseInt(args[0]));
    	}
    
    	public static int getEvenNumber(int number) 
        {
            int retValue = number * 2;
            assert retValue % 2 == 0;
            return retValue;
    	}
    }

    Another way to use assertions is to test for class invariants. A class invariant is a condition that should always be true about a class. Imagine we have a class representing a deck of cards. Once the class is instantiated it should contain an array of 52 entries each with a different random number between 1 and 52 without duplicates. We can create a method to test this assumption and then execute this method to verify that the class is working correctly. For example:

         DeckOfCards dc = new DeckOfCards();
         assert dc.assertionValidate();

    Final Thoughts

    Sun has an excellent tutorial on using assertions. You can see it at:

    http://java.sun.com/j2se/1.4/docs/guide/lang/assert.html

    According to Sun, the runtime cost of using assertions when they are turned off is negligible. This means that we can leave our assertions in our code for production without paying a price for skipping over them. Using assertions should help to improve the quality of the code you produce. We can now test all of our assumptions easily, insuring that our code is as bullet-proof as we think. So give assertions a try.


    Return to Top
    Sun Certified Java Programmers Exam for JDK 1.4
    Marcus Green August 2002

    When is it available/can I take the beta?
    According to the Sun website at http://suned.sun.com/US/certification/java/java_progj2se.html The exam will be available in August 2002. The beta versions of new exams are available for a short time several months before the real thing. Once they have finished the beta test you will have to wait for the real thing before you can take it. Remember that the beta is just that, a test version so you are probably better off taking the real thing as it will have been tested and adjusted.

    How have the objectives changed?
    No more GUI topics
    The new version of the exam no longer covers GUI programming, this means no more questions on the AWT (Swing has never been on the programmers exam). More surprisingly the new version of the exam no longer covers I/O, so this means no coverage of the new nio classes in JDK 1.4.

    Assertions
    The big new objective for the exam is the assert keyword in JDK 1.4. This is incuded in section 2 of the objectives under the headings Write code that makes proper use of assertions, and distinguish appropriate from inappropriate uses of assertions. Identify correct statements about the assertion mechanism. You can find an article on assertions at http://java.sun.com/j2se/1.4/docs/guide/lang/assert.html Several books on the market also cover this topic, including Peter van der Lindens Just Java version 5. This is not a big topic and you should not need to spend a huge amount of time learning about it.

    The wrapper classes
    Section 8 of the objectives
    FUNDAMENTAL CLASSES IN THE JAVA.LANG PACKAGE
    Now includes the objective:
    Describe the significance of wrapper classes, including making appropriate selections in the wrapper classes to suit specified behavior requirements, stating the result of executing a fragment of code that includes an instance of one of the wrapper classes, and writing code using the following methods of the wrapper classes (e.g., Integer, Double, etc.):
    doubleValue
    floatValue
    intValue
    longValue
    parseXxx
    getXxx
    toString
    toHexString
    This seems a small and easily covered topic You can find out the basics in the API docs at http://java.sun.com/j2se/1.4/docs/api/java/lang/package-summary.html

    Using hashcode
    Objective 9.2 now reads
    Distinguish between correct and incorrect implementations of hashcode methods.
    You can find out a little more about hashcodes from the sample chapter 3 that is available for the book Effective Java which is available in pdf format from http://developer.java.sun.com/developer/Books/effectivejava/

    Which version of the exam should I take?
    Being certified is generally the important thing rather than what version of the certification you have and a crucial part of being certified is having good study material. At the time of writing there is approximatly no material specifically for the 1.4 exam and heaps of material for the 1.2 exam it easy to make a case for the going for the 1.2 exam untill study material catchess up. Also if you want to demonstrate your ability as a GUI programmer the 1.4 exam is not appropriate. It is unlikely that an employer or project will place huge emphasis on a knowledge of the wrapper classes or the assert statement as a pre-requisite for a job but you may find positions that require gui knowledge.

    How hard will the 1.4 exam be?
    The passmark has been dropped to 52% (http://suned.sun.com/US/certification/faq/#java) so it is possible to make an argument that either the questions are harder or the exam will be easier. With I/O and AWT removed from the question bank I would guess there will be a renewed emphasis on fundamentals such as threading, package/class structure and OO. Remember that Sun want people to pass so they are not going to do anything to trick you, you just need to know the basics of the language.

    Are the new objectives a ?good thing??
    Much new development is for the web where GUI skills are not required so removal of the AWT objtives is a good thing, plus most people doing GUI work were probably using the Swing classes anyway. I am not so sure that removal of the I/O classes is such a good thing as most programmers at some time will require to do I/O programming. However it does make way to emphasise more of the basics of the language.

    What free study materials are available for the new exam?
    Writing comprehensive study material is a long and time consuming task and there will be a time lag until free materials catch up. Note that the changes only represent a small percentage of the objectives, I would estimate less than 10% by comparison with the 1.2 exam so 90% of current material will still be valid. Why not make yourself semi famous and write some material on the new topics.


    Return to Top

    An Introduction to java.util.regex - Lesson 1

    by Dirk Schreckmann

    This series of lessons covering regular expressions in Java was modeled after the tutorial created to teach the com.stevesoft.pat package1. The com.stevesoft.pat package is available for download and use from JavaRegex.com. It's an excellent alternative package to harvest the power of regular expressions in Java.

    Part 1: Basic Pattern Elements

    What is a regular expression and what are they good for?

    For the purposes of this tutorial, let's loosely define a regular expression as a pattern of text. For a more formal definition of regular expression, try a search on google for Chomsky + hierarchy + regular + expression.

    Regular expressions can be used to verify a data input format (such as a phone number, a zip code, an email address, a social security number, or even the JavaRanch naming policy), to search for text data that matches a specified pattern, or to find potential grammatical errors such as repetitious words (which a spell checking algorithm might not find).

    The java.util.regex package provides two classes for comparing a regular expression against an input String (actually against any CharSequence object2). A Pattern object is a compiled representation of a regular expression3. A Matcher object is an engine that performs match operations on a character sequence by interpreting a Pattern4. The Pattern class contains two static factory methods, compile( String ) and compile( String , int ) , that create and return a Pattern object. The Pattern instance method matcher( CharSequence ) creates and returns a Matcher object based on the Pattern instance and the input CharSequence.

    Four methods are available to a Matcher object to match part or all of an input String against a regular expression pattern. From the Matcher class documentation4:

    • The boolean matches() method attempts to match the entire input sequence against the pattern.
    • The boolean lookingAt() method attempts to match part or all of the input sequence, starting at the beginning, against the pattern.
    • The boolean find() and boolean find( int ) methods scan the input sequence looking for the next subsequence that matches the pattern.

    Each of these methods will return true if the pattern matched part or all of the input String as appropriate. As a side effect, the find methods set internal state information in the Matcher object that is used to track the last location where a match occurred.


    Plain Text

    The most basic regular expression is a literal text string. The alphanumeric characters are interpreted literally1.

    The word "shells" can be found in a String as follows:

        String input = "She sells sea shells by the sea shore." ;
        
        // Create a Pattern object.  A Pattern is a 
        // compiled representation of a regular expression.
        Pattern pattern = Pattern.compile( "shells" );
        
        // Create a Matcher object.  A Matcher is an engine that 
        // performs match operations on a character sequence by 
        // interpreting a Pattern.
        Matcher matcher = pattern.matcher( input );
        
        System.out.println( matcher.matches() );
        // Prints false.  matcher.matches() attempts to 
        // match the entire input sequence against the pattern.  
        // The match would have succeeded, if the pattern described 
        // the entire input String.
        
        System.out.println( matcher.lookingAt() );
        // Prints false.  matcher.lookingAt() attempts to 
        // match the input sequence, starting at the beginning, 
        // against the pattern.  The match would have succeeded, 
        // if the pattern were "She".
        
        System.out.println( matcher.find() );
        // Prints true.  matcher.find() attempts to find 
        // the next subsequence of the input sequence that 
        // matches the pattern.

    Matcher and Pattern objects have methods to return the parts of an input String matched against a pattern. The String group() method of the Matcher class returns the input subsequence matched by the previous match4. The String[] split( CharSequence ) method of the Pattern class splits the specified input character sequence around matches of a pattern3. (Since Java 1.4, String objects also have two split methods that take a regular expression as a parameter and split the String object around matches of the regular expression, returning a String array of the result.)

        // The Matcher must be reset and searched again after 
        // failed attempts at matching.  The Matcher would  
        // otherwise not be in a proper state to get the 
        // information related to the last match and methods 
        // that query for such information would throw an 
        // IllegalStateException.  Note that the find() method 
        // resets the Matcher if previous attempts at matching 
        // failed.
        
        System.out.println( matcher.find() );       // Prints true.
        
        System.out.println( matcher.group() );      // Prints shells.
        
        String[] splits = pattern.split( input );
        System.out.println( splits.length );        // Prints 2.
        
        for ( int i = 0 ; i < splits.length ; i++ ) // Prints 
        {                                           // She sells sea
            System.out.println( splits[ i ] );      //  by the sea shore.
        }

    Note that regular expression patterns in Java are by default case sensitive. So, using the same input, a search for "Shells" would have failed.

        pattern = Pattern.compile( "Shells" );
        
        // Since a new Pattern is to be used, a new Matcher 
        // must also be used.
        matcher = pattern.matcher( input );
        
        System.out.println( matcher.find() ); // Prints false.

    Meta characters

    Meta characters, in regular expressions, are characters that allow the description of more flexible text patterns than exact text (such as "shells" or "shore"). Meta characters are not interpreted literally. Meta characters used in describing Java regular expressions include "." , "?" , "+" , "*" , "{" , "}" , "(" , ")" , "[" , "]" , "$" , "^" , "|" , "&&" , "<" , "!" , "=" , ":" , and "\" . Some of these meta characters and their uses are introduced in this lesson. Further meta characters and their uses will be covered in following lessons.


    Repetition Quantifiers

    Characters such as "?" , "+" , "*" , and "{}" provide the ability to match a pattern element multiple (or zero) times.

    ? Matches the preceding element zero or one times.
    + Matches the preceding element one or more times.
    * Matches the preceding element zero or more times.
    {n} Matches the preceding element n number of times.
    {min,max} Matches the preceding element a specified number of times from min to max inclusive.
    {min,} Matches the preceding element min or more times.

    These elements must be prefixed by another pattern element to be matched.

        input = "Some say, ABBA is a grooooovy music group." ;
        
        pattern = Pattern.compile( "is?" );
        // Matches the "i" character or the "i" character 
        // followed by an "s".
        
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints is.
        
        pattern = Pattern.compile( "x?" );
        // Matches the "x" character or nothing.
        
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints the empty String.
        
        pattern = Pattern.compile( "AB+A" );
        // Matches the sequence of characters that begins 
        // and ends with "A" with one or more "B" characters 
        // in the middle.
        
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints ABBA.
        
        pattern = Pattern.compile( "AB*C*A" );
        // Matches the sequence of characters that begins 
        // and ends with "A" and has zero or more "B" 
        // characters followed by zero or more "C" characters 
        // in the middle.
        
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints ABBA.
        
        pattern = Pattern.compile( "gro{2,}vy" );
        // Matches the sequence of characters that begins 
        // "gr" , ends with "vy" , and has two or more "o" 
        // characters in the middle.
        
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints grooooovy.
        
        pattern = Pattern.compile( "gro?vy" );
        // Matches the sequence of characters that begins 
        // "gr" , ends with "vy" , and has zero or one "o" 
        // characters in the middle.
        
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints false.

    Character Classes

    Square brackets, "[]" , allow the description of a set of characters (known as a character class), of which one and only one character must match.

        pattern = Pattern.compile( "[Rr]egular" );
        // Matches "Regular" or "regular".
        
        input = "I like regular expressions." ;
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints regular.
        
        input = "Regular expressions are great." ;
        matcher.reset( input );
        // Since the same Pattern is to be used to match 
        // against a new input, the Matcher need only 
        // be reset using the new input sequence 
        // (a new Matcher need not be obtained.)
        
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints Regular.

    To match any single lowercase letter of the english alphabet, it's possible to specify such a pattern as:

      " [abcdefghijklmnopqrstuvwxyz]"

    Fortunately, a few "shortcut" regular expression constructs are available. To match a range of characters, the "-" character can be used. So, "[a-z]" describes the same range of characters above.

    The regular expression syntax allows two styles to describe the union of two or more character classes. "[a-c[f-h]]" and "[a-cf-h]" both describe the character class "[abcfgh]".

    Other "shortcut" constructs include these often used predefined character classes3:

    .matches a single character (may or may not match line terminators)
    \dmatches a digit: [0-9]
    \D matches a non-digit: [^0-9] *
    \s matches a whitespace character: [ \t\n\x0B\f\r] (see footnote on characters)
    \S matches a non-whitespace character: [^\s] *
    \wmatches a word character: [a-zA-Z_0-9]
    \W matches a non-word character: [^\w] *
     * "^" is the NOT operator and is covered further down on this page.

    Note that the backslash character must be escaped (quoted) when used in a Java String in order for it to be interpreted as a String literal. So, when specifying a predefined character to use, don't forget to escape the backslash with another backslash. For example, to match the word eat surrounded by whitespace, the pattern \seat\s must be specified as "\\seat\\s".

        pattern = Pattern.compile( "\\seat\\s" );
        // Matches "eat" surrounded by whitespace.
        
        input = "When do we eat?" ;
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints false.
        
        input = "We eat when we're hungry." ;
        matcher.reset( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints " eat ".

    The OR , NOT , and AND Operators

    "|" is the OR operator. When used outside of a character class, it allows the matching of one or the other pattern. Inside of a character class, "|" is interpreted as a literal character and serves no meta character function.

        pattern = Pattern.compile( "apple|orange" );
        // Matches "apples" or "oranges".
        
        input = "I ate my orange." ;
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints orange.
        
        input = "I ate my apple." ;
        matcher.reset( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints apple.
        
        input = "I don't have any more fruit." ;
        matcher.reset( input );
        System.out.println( matcher.find() );  // Prints false.

    "^" is the NOT operator when prefixed inside a character class. "[^b]" would match any character other than a "b". Note that it does not match the empty string. Outside a character class, "^" takes on a different meaning and is covered in a later lesson.

        pattern = Pattern.compile( "[^b]lop" );
        // Matches any four characters, of which the first 
        // cannot be "b" and the last three must be "lop".
        
        input = "blop" ;
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints false.
        
        input = "flop" ;
        matcher.reset( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints flop.
        
        input = "lop" ;
        matcher.reset( input );
        System.out.println( matcher.find() );  // Prints false.
                                               // The empty String does 
                                               // not match "^b".

    "&&" is the AND operator. It allows the definition of two conditions for a pattern element to match.

        pattern = Pattern.compile( "[a-z&&[^aeiou]].{5}" );
        // Matches any six characters where the first character 
        // is a lower case letter that is not a vowel.
        
        input = "Every lamb counts fish." ;
        matcher = pattern.matcher( input );
        
        while ( matcher.find() ) 
        {
            System.out.println( matcher.group() ); // Prints "very l"
                                                   //        "mb cou"
                                                   //        "nts fi"
        }

    Maximal and Minimal (Greedy and Reluctant) Matching Behavior

    Note that the default behavior of the regular expression elements presented so far is to be greedy (hungry) and match as much of the input as possible (a maximal match).

        input = "1001 0101 0011 1100" ;
        
        pattern = Pattern.compile( "1.*1" );
        // Matches the sequence of characters where the first 
        // and last character is "1" with zero or more characters 
        // in between.
        
        matcher = pattern.matcher( input );
        System.out.println( matcher.find() );  // Prints true.
        System.out.println( matcher.group() ); // Prints 1001 0101 0011 11.

    A minimal match, also known as a reluctant match, would match as little of the input sequence as possible in order to satisfy the entire regular expression. In this example, such a match would have matched the input sequence four times, the first matching subsequence being "1001". To specify a minimal match, follow the appropriate repetition quantifier construct with a "?" . "?" modifies the behavior of the repetition quantifier to match reluctantly.

        input = "1001 0101 0011 1100" ;
        
        pattern = Pattern.compile( "1.*?1" );
        // Matches the sequence of characters where the first 
        // and last character is "1" with as few as possible 
        // characters in between to make the pattern match.
        
        matcher = pattern.matcher( input );
        
        while ( matcher.find() )                 // Prints 
        {                                        //  1001
          System.out.println( matcher.group() ); //  101
        }                                        //  11
                                                 //  11

    ?? Matches the preceding element up to one time, as few times as possible.*
    +? Matches the preceding element one or more times, as few times as possible.*
    *? Matches the preceding element zero or more times, as few times as possible.*
    {min,max}? Matches the preceding element from min to max inclusive, as few times as possible.*
    {min,}? Matches the preceding element min or more times, as few times as possible.*
      * Note that "as few times as possible" means "as few times as possible in order to satisfy the entire regular expression being matched."





    Notes and Resources
    1 The Regular Expressions Tutorial at JavaRegex.com
    2 java.lang.CharSequence is a new Interface in Java 1.4. A CharSequence is a readable sequence of characters. This interface provides uniform, read-only access to many different kinds of character sequences. String and StringBuffer both implement CharSequence. -- CharSequence API Documentation
    3 java.util.regex.Pattern API Documentation
    4 java.util.regex.Matcher API Documentation
    5 java.util.regex Package API Documentation
    6 From The Pattern Class Documentation:

    Valid Characters in regular expressions
    x      - The character x 
    \\     - The backslash character 
    \0n    - The character with octal value 0n (0 <= n <= 7) 
    \0nn   - The character with octal value 0nn (0 <= n <= 7) 
    \0mnn  - The character with octal value 0mnn (0 <= m <= 3, 0 <= n <= 7) 
    \xhh   - The chara

    cter with hexadecimal value 0xhh 
    \uhhhh - The character with hexadecimal value 0xhhhh 
    \t     - The tab character ('\u0009') 
    \n     - The newline (line feed) character ('\u000A') 
    \r     - The carriage-return character ('\u000D') 
    \f     - The form-feed character ('\u000C') 
    \a     - The alert (bell) character ('\u0007') 
    \e     - The escape character ('\u001B') 
    \cx    - The control character corresponding to x 
    7 The Regular Expression Library
    8 For further reading on regular expressions, take a look at Mastering Regular Expressions by Jeffrey Friedl. A sample chapter from O'Reilly is available on-line.
    9 The code examples in this article were formatted using the JavaCodeSyntaxHighlighter filter created by John Sun for use with Jive Software's Jive Forums application.



    A special thank you to (in alphabetical order) Cindy Glass, Mapraputa Is, Thomas Paul, Matthew Phillips, Mark Spritzler, Janet Wilson, and Jim Yingst for their valuable feedback and help in improving this lesson from its first draft edition.


    Last Updated: 2002.08.30 17:51

    Return to Top

    Java and C# - A Programmer's Comparison

    by Thomas Paul

    Introduction


    There are articles all over the internet comparing C# and Java so why am I writing one? I started programming in Java in 1996 after several years of developing applications in C++. Since April of 2002, I have been writing programs in C#. That means over the last 10 years I have developed real life production applications in C++, Java, and C#. I also don't have any ax to grind. I think I can be fair in an evaluation of C#, something that seems to be missing in many of the evaluations I have read.

    The question of why C# was invented has more to do with the politics between Sun and Microsoft than anything else. Once Microsoft was excluded from the Java world, the development of C# was virtually assured. Microsoft needed a new language to go with their .Net environment and C++ and VB were simply too complicated or too limited for this new environment.

    So is C#, Microsoft's brand of Java? To put it simply, yes. C# is a lot like Java and a Java developer will find the transition between the two languages to be very simple. You will find that many things in the language are identical, some other things are very similar, while a few others are very different. Rather than do a complete comparison of the two languages, I would like to discuss those things that Java programmers (in my opinion) will either wish Java had or will hate.

    Things I Hate in C#

    Operator Overloading


    This was in C++ and I hated it in that language. For those who are unfamiliar with the idea behind operator overloading, I will give you an example out of Java. The String class has the plus sign overloaded so that you can concatenate two Strings. This is a convenience so that we can code s1 = s2 + s3 instead of s1 = s2.concat(s3). However, when operator overloading is unlimited, we end up with odd constructs. In C#, you can overload any operator including ==, !=, < , and >. So instead of using an equals method to compare two objects, you can overload the equals operator to compare any two objects. This might sound nice, but can easily cause confusion. Is obj1 == obj2 a reference compare or an object contents compare? There's no way to know unless you look at the API. Of course, we have the same problem with the equals method in Java since it may or may not be overridden but at least we always know that == is a reference compare. In C#, if == is overloaded, there is no way to do a reference compare! You might think that this isn't too bad but what about other operators? What does it mean if I do employee1 = employee2 + employee3? Although there may be times when it is useful (date1 = date2 - date3) , it tends to create more confusion than it is worth.

    One capability with operator overloading that is very nice is the ability to create castings between classes. C# allows you to create explicit or implicit casts between classes that would not normally be permitted. For example, let's say that we have an Employee class that is the parent of ExemptEmployee and NonExemptEmployee. In Java there is no way to cast a NonExemptEmployee to be an ExemptEmployee. C# allows you to set up a method to do just that. The method will take in a NonExemptEmployee and return an ExemptEmployee. The method gets executed automatically when casting is needed (implicit) or when a cast is made (explicit). This can be very useful if you have a method that takes in ExemptEmployee objects but all you have is a NonExemptEmployee object.

    Properties and Indexers


    We all know by now that properties should be kept private and then accessed through public get and set methods. The makers of C# agree with this concept but rather than use Java-like public get and set methods, they designed a way to make it look like you are accessing public properties even though you are really running get and set methods. In this way you can code office1.DeptNum = 101 and actually be running a set method. The code looks like this:
    public int DeptNum 
    {
    	get 
    	{
    		return deptNum;
    	}
    	set
    	{
    		deptNum  = value;
    	}
    }

    I find this to be confusing and the saving over coding office1.setDepartment(101) is trivial.

    Indexers are also confusing. The idea with an indexer is that you can make an object appear to be an array. For example, let's assume that you have a department class that you want to use to hold multiple office objects. Rather than use a method like dept1.addOffice(office1), you can use dept1[0] = office1. To a Java programmer, dept1 looks like an array of Office objects. In fact, dept1 is a Department class that can hold all sorts of information about departments including an array of offices in that department. The big problem is that it isn't clear exactly what kind of object should be added using the indexer. With an addOffice method you know you are adding an Office object. But using dept1[0] isn't clear at all.

    Properties and indexers drive me crazy because they seem to be deliberately designed to fool programmers into believing something about a class that isn't true.

    Pass by Reference


    Just as in Java, C# uses pass by value. But C# also allow the programmer to pass by reference. Although parameters passed by reference must be clearly identified, the whole concept of pass by reference seems very anti-OO to me because you are accepting side effects as being desirable. Methods should return values, not replace values passed to them. This isn't a terrible thing, but I could have easily lived without it.

    Catching Exceptions


    C# does not require you to catch exceptions. I don't understand why this is the case because forcing exceptions to be caught makes for cleaner, more reliable code. In Java, if you fail to catch an exception, you get a nice compile error that let's you know what exceptions a method can throw. This makes it easy to write reliable code without having to check the API every time you make a method call. C# does not give any warnings when you fail to code a catch around a method call. This forces you to check the API to figure out what exceptions might be thrown. A definite pain in the neck. The end result is that try...catch isn't used nearly as often as it should be in C#.

    Polymorphism


    C# uses the C++ model for polymorphism which means you must take positive action to make a method eligible to take part in polymorphism. What does this mean exactly? In Java, you can override a method in your parent class and as long as the parent method isn't final there isn't a problem. You get runtime method binding which is very powerful. C# prefers to use compile-time binding unless you specifically tell it otherwise. C# adds three keywords to make this all work; virtual, override, and new. Since programmers tend to not code their classes with the next programmer's concern in mind, it is very unlikely that the original programmer will write the necessary code to insure that programmers extending their class will be able to override their methods. Java wins hands down in this area.

    Things I Love in C#

    foreach


    The foreach statement is one of the most convenient ways to iterate through a collection or an array. It allows you to process an entire collection and cast the objects to the correct type in one handy little statement. Here's an example:
    public void AMethod(ArrayList list) 
    {
    	foreach (Employee emp in list)
    	{
    		Console.WriteLine(emp.Name);
    	}
    }

    To do the same thing in Java would require creating an iterator and running a while loop. The only problem with this is that if list contains something other than an Employee object, the foreach will throw a ClassCastException.

    Enumerators


    This is something that really belongs in Java. It helps create more reliable code by insuring type safety at compile time. For example, if you have a field that should only contain the days of the week, to insure type safety at compile time, you would have to create a special class to insure that only the days of the week can end up in the field. This can only be tested at runtime. Using an Enumerator, you can test what is being moved to the field at compile time. How do we do this?

    First we create an enumerator which contains the days of the week:
    enum DayOfTheWeek
    {
    	Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
    }


    Now we define our field as being of type DayOfTheWeek. By doing so, our variable can only hold one of the seven DayOfTheWeek enumerations:
    DayOfTheWeek day; 
    day = DayOfTheWeek.Sunday;

    Automatic Boxing of Primitives


    You have an int and you want to stick it into a collection. Or you have a float and you want to convert it into a string. In C# this is a breeze. Whenever you use a primitive in a place that requires an object, C# automatically turns the primitive into an object. This is called "boxing". basically it means that you can treat all your primitives as if they were objects without paying the overhead of having them always be objects. So you can do something like this:
    int i = 50;
    arrayList.Add(i);
    string s = i.ToString( );

    Delegates


    One of the nice things about C++ is the ability to use function pointers. Delegates give you a very similar functionality. In many ways it is similar to the event model used in Java but it has the added advantage of not tying you to a particular method name. One of the problems with Java's event model is that if you use one class to receive event notifications from different objects (let's say one class is handling the action event for three Buttons) then all the notifications will go to the same method. The method has to figure out which Button caused the method to be triggered. The delegate model allows you to have different methods for each Button object if you wish. Instead of passing just an object to be notified, the delegate model allows you to pass a method to be called when the event is triggered.

    OKButton.Click += new System.EventHandler(buttonHandler.OKButton_Click);
    CancelButton.Click += new System.EventHandler(buttonHandler.CancelButton_Click);

    Notice that setting up a delegate involves using operator overloading. In this case, when the OKButtum is clicked, the OKButton_Click method of the buttonHandler object will be invoked. When the CancelButton is clicked, the CancelButton_Click method will be invoked. The actual method has to have a certain signature that is determined by the delegate model that is used. For button clicks, the method signature looks like this:

    private void OKButton_Click(object sender, System.EventArgs e) { }

    Although the delegate model is used for events, it can be used for any situation where a callback is useful.

    The C# switch statement


    There are two nice improvements in the switch. First, you can use a string in your case. Second, there is no way to accidentally fall through from one case to another. If you want to fall through you have to specifically tell the compiler.

    Multi-dimensional Arrays


    C# provides direct support for multi-dimensional arrays. It also supports the jagged arrays found in Java. You can code this kind of construct:

    string[,] cityState = new string[25,2];

    The as keyword


    C# has the "is" keyword which is basically the same as instanceof. You can code something like: if (a is Animal). But C# also has the "as" keyword which is used for casting.

    Look at this piece of Java code (assume that Animal is the parent class of Dog):
    Dog d;
    Animal a = new Animal();
    d = (Dog)a;  // ClassCastException

    Although this code compiles, it causes a runtime ClassCastException. We would need to use an instanceof before the cast to insure that the cast will work. That is what the "as" does in C#. You can do this:
    Dog d;
    Animal a = new Animal();
    d = a as Dog;

    If this is not a valid cast (a is not a Dog or a child of Dog), d will contain null and no ClassCastException occurs. Of course, C# allows you to use a regular cast as well.

    Final words


    So which is the better language? They are both great languages and I enjoy working in both of them. Both languages have all the features that you expect in a modern object oriented language. Knowledge of one of these is easily transferred to the other. Thebest part is that C# has opened the Microsoft world to Java developers. By removing the reliance on C++ and Visual Basic, .Net has created an opportunity for Java programmers to take their skills into a job market that was previously closed to them.

    By the way, some of the things I pointed out as things I like about C# are planned to be added to Java at some point. You can take a look at the "From Mantis to Tiger" site for a look at some of the proposed enhancements in J2SE 1.5.


    Return to Top
    Cattle Drive Column - 20020831
    Movin' them doggies on the Cattle Drive

    It's where you come to learn Java, and just like the cattle drivers of the old west, you're expected to pull your weight along the way.

    The Cattle Drive forum is where the drivers get together to complain, uh rather, discuss their assignments and encourage each other. Thanks to the enthusiastic initiative of Johannes de Jong, you can keep track of your progress on the drive with the Assignment Log. If you're tough enough to get through the nitpicking, you'll start collecting moose heads at the Cattle Drive Hall of Fame.

    Gettin' them doggies...
    This month finished with 17 drivers busy testin' the waters and pickin' on them po' nitpickers. The Say assignment alone's been keepin' four of them from watchin' too much of that color TV while more than half of the drivers are busy with Servlets and JDBC.

    Another moose on the wall for...
    Yep, that's right, you make it through, you get yerself a nice little moose to hang on the wall. Well, OK, so it's a virtual moose on a virtual wall, but you can be right proud of 'em! Thanks to the efforts of Marilyn deQueiroz, you can now proudly admire your codin' accomplishments at the recently opened Cattle Drive Hall of Fame. Check it out, pardner, it's worth a wink.

    This month Peter Berquist bagged his first moose on the Java Basics trail of the drive. Way to go Peter! Louise Haydu, Manju Jain, and Dirk Schreckmann each hung their third moose head up on the wall after pokin' at them nitpickers on the Servlets trail. All them poor meese... what would the WWF say?

    Saddle sore...
    So close and yet so far, that's how it feels when you're just about to get through one of the Cattle Drive sections. Long time driver, Carol Murphy, is about set to bag her third moose and order up some sarsaparilla at the saloon. Hang in there, cowpoke, yer almost there!

    Back from being out on the range...
    Sometimes long lost Cattle Drivers untangle themselves from the sagebrush and actually make it back to the Drive. Pauline McNamara found some time between nitpickin' and bicycling through Europe to take another shot at those Servlets assignments. Good luck pardner!

    Nitpicking is hard work too...
    We know they're workin' reeeeeally hard, after all, we've seen what those assignments look like once the nitpickers have combed through 'em. Hats off to Marilyn deQueiroz and Pauline McNamara for their dedication and patience with the pesky vermin that always manage to make their way into those assignments.

    Tips for the Trail...
    Java's only ternary operator - sometimes called the query-colon operator - condition ? exp1 : exp2 - just might be the thing to use in order to keep that code nice and easy to read. Like we've mentioned time and again, readability is one of the most important goals of the Cattle Drive, and for writing code in general!

    Content and format adapted from Ol' Timer Pauline McNamara's original column by Dirk Schreckmann.


    Return to Top
    Book Review of the Month

    JSTL in Action
    by Shawn Bayern
    A nicely written book about JSTL (JSP Standard Tag Library). Its expected audience consists of HTML and JSP developers who can be unfamiliar with Java, as well as experienced Java programmers.

    A reader without programming experience will probably benefit most. The book is beginner-friendly on all levels of organization. Terminology is relaxed without being sloppy: correspondence to both formal lexicon and "field jargon" is given. Every important word and concept is explained, often with vivid (or bizarre, depending on your taste) metaphors. It will be long time before I forget author's definition of "scope" that compared it to flying rats...

    The words "in action" in the book's title aren't just words, it is a methodological principle. The discussion concentrates on practice rather than theory and specifications; each JSTL tag comes with examples - from "elementary" tasks - how to set encoding or print numbers in assorted formats, to parsing XML and performing SQL queries. There are more complex projects, like writing an online survey, message board and a simple web portal from scratch - toys that look so real and their code so simple that you want to try it out.

    The last part is targeted at Java programmers and deals with issues like performance improving, configuration, and developing custom tags - JSTL supports even this!

    And if all this is not enough, then you should know: there are jokes scattered throughout the book, so you do not want to skip pages for not to miss one!

    (Margarita Isayeva (Map)- Sheriff, August 2002)

    More info at Amazon.com || More info at Amazon.co.uk

    Chosen by Cindy Glass and Madhav Lakkapragada

    Return to Top
    September Giveaways

    Starting Date Book Author(s) Publisher JavaRanch Forum
    Sept 3 iPlanet Application Server: Designing and Building J2EE Solutions David Ogren Wiley Sun[tm] ONE Application Server
    Sept 10 Professional JSP Tag Libraries Simon Brown Wrox JSP
    Sept 17 RefactorIT Tanel Alumae Aqris OO, Patterns, UML and Refactoring
    Sept 24 TBD      

    For more information on JavaRanch's Giveaways see Book Promotion Page.

    Return to Top
    September News

    Hey, we've added a Tack Room. No one should be out on the range without their vital JavaRanch supplies. T-shirts, caps, lunch bags, and mugs will keep you ready whether you are out on a cattle drive or just dropping in to the saloon.

    As always JavaRanch is dedicated to providing you with the best source of information on Java Programming and Engineering.

    by Carl Trusiak


    Return to Top

    Managing Editor: Carl Trusiak

    Comments or suggestions for JavaRanch's NewsLetter can be sent to the NewsLetter Staff
    For advertising opportunities contact NewsLetter Advertising Staff