|
Articles in this issue :
|
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:
- All operations against the Collection or Map must be done through the returned synchronized object and not
the object passed into the synchronization method.
- 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
|
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!
|
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:
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
|
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
Pattern Elements Introduced in this Lesson
plain text
repetition quantifiers --
? , * , + , {n} , {min,max}
character classes -- [] , . , \w , \s , \d , \W , \S , \D
OR , NOT , AND -- | , ^ , &&
Maximal and Minimal Matching -- X?
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 Pattern 4.
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.
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.
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. |
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) |
\d | matches 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] * |
\w | matches 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 ". |
"|" 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"
} |
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." |
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
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
|