eyt*

Find your next scenic drive!

December 3, 2011

Rounding numbers with Java’s NumberFormat...

Take a look at the following numbers and round them to the nearest whole number:

  1. 2
  2. 2.1
  3. 2.2
  4. 2.3
  5. 2.4
  6. 2.49
  7. 2.5
  8. 2.51
  9. 2.6
  10. 2.7
  11. 2.8
  12. 2.9
  13. 3

I’m pretty confident that you will get the same answers as my 4th grader, which is that the numbers from 1-6 result in a 2 and 7 onwards results in 3, right? Well, given the following code though, you’d be surprised:

  1. import java.text.DecimalFormat;
  2. import java.text.NumberFormat;
  3. public class test {
  4.   public static void main( String [] args ) {
  5.      double [] values = new double[] { 2, 2.1, 2.2, 2.3, 2.4, 2.49, 2.5, 2.51, 2.6, 2.7, 2.8, 2.9, 3.0 };
  6.      final NumberFormat format = new DecimalFormat( "#" );
  7.      for ( double d : values ) {
  8.         System.out.println( d + ": " + format.format( d ) );
  9.      }
  10.   }
  11. }

Your surprise would come from the fact that the 2.5 rounds down to 2. Why? Well, reading the DecimalFormat javadocs closely, you will notice that the default rounding policy is HALF_EVEN, in which the above behaviour is explained. To change that, simply use format.setRoundingMode( RoundingMode.HALF_UP ); or one of the other policies available in the rounding mode.

Why this is the default behaviour is puzzling to me, but I’ll just add it to the list, which includes the Math.abs() handling of Integer.MIN_VALUE and non-thread-safe SimpleDateFormat (which, for the record, I do not believe that the code suggested in that blog post is guaranteed to be thread-safe either... since the DateFormat class is declared to be non-threadsafe also).

September 17, 2008

Math.abs has an edge case...

Consider the following Java code:

  1.   int ai = Math.abs( i );
  2.   assert ai >= 0;

Will the assert ever fire?

Yes, it turns out that it can fire if i = Integer.MIN_VALUE, and you have been warned about this in the Math.abs javadoc, which states “Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative.

Keep this in mind when looking at such innocent looking code...

September 11, 2008

Java Mail: Make sure the mail.smtp.auth property's value is a String...

If you are using the JavaMail API to send out e-mail via an e-mail server that requires authentication and are getting an error like com.sun.mail.smtp.SMTPSendFailedException: 550 You must authenticate, make sure the mail.smtp.auth property is assigned as a String, like this:

  1.   properties.put( "mail.smtp.auth", "true" );

Not exactly the most obvious bug to find...

May 23, 2008

Using Ant with Cygwin

If you have ever tried building something with ant under Cygwin, you probably have noticed an error such as the following:

build.xml:35: c:\cygdrive\c\Progra~1\java/SunAppServer\jdk\lib\J2EE.jar

The current Ant documentation suggests that you should change your build.xml to wrap all such environment labels and class paths with code that executes cygpath, but this turns out to create some ugly code, especially if your build scripts use a lot of environment labels.

An alternative scheme that I have just come up with is to use a layer of indication. You can create an ant shell script that translates all of your necessary Cygwin environment labels using cygpath, and then call the ant.bat to do the actual build. The advantage of this approach is that more build.xml files are cross-platform out of the box and require very few, if any, tweaks.

The following file is an example of my approach:

#!/bin/sh
# OS-Specific Stuff
export PATH=`/usr/bin/cygpath --path --windows $PATH`
export TEMP=`/usr/bin/cygpath --path --windows $TEMP`
export TMP=`/usr/bin/cygpath --path --windows $TMP`

# Java Specific Stuff
export JAVA_HOME=`/usr/bin/cygpath --windows $JAVA_HOME`
export J2EE_HOME=`/usr/bin/cygpath --windows $J2EE_HOME`
export TOMCAT_HOME=`/usr/bin/cygpath --path --windows $TOMCAT_HOME`
export CLASSPATH=`/usr/bin/cygpath --path --windows $CLASSPATH`

# Ant Specific Stuff
ORIGINAL_ANT_HOME=$ANT_HOME
export ANT_HOME=`/usr/bin/cygpath --path --windows $ANT_HOME`

# Project-Specific Stuff
export WHATEVER_YOU_NEED=`/usr/bin/cygpath --windows $WHATEVER_YOU_NEED`

# Invoke the ANT.BAT via the original ANT_HOME value
$ORIGINAL_ANT_HOME/bin/ant.bat $1 $2 $3 $4 $5 $6 $7 $8 $9

Of course, this technique can be generally applied to other applications that use environment labels. Hope that helps.

February 11, 2007

C++ Strongly-Typed Enumerations...

With the release on Java 5, we finally have enumerations in Java, but they really outdone themselves, in that an enumerated type is actually a class, where you can add your own methods. Take, for example, this code:

  1. public enum Color {
  2.   Red,
  3.   Yellow,
  4.   Orange,
  5.   Green,
  6.   Blue,
  7.   Brown,
  8.   Black,
  9.   Purple;
  10.  
  11.   public boolean isPrimaryColor() {
  12.     switch ( this ) {
  13.     case Red:
  14.     case Blue:
  15.     case Yellow:
  16.       return true;
  17.  
  18.     default:
  19.       return false;
  20.     }
  21.   }
  22. }

Instead of having a utility class off to the side that takes an enumeration as a parameter, you can now add that method directly to the enumeration, and I do not think that there would be much controversy that color.isPrimaryColor(); reads better than ColorUtils.isPrimaryColor( color );.

Putting this aside for a moment, C++09 is cleaning up their enumerations by adding support for strongly type enums (PDF Proposal).

In the current version of C++, we have problems with code like this:

  1. enum Color { RED, YELLOW, ORANGE, GREEN, BLUE, BROWN, BLACK, PURPLE };
  2. enum TerrorAlertLevel { RED, ORANGE, YELLOW, BLUE, GREEN };

This does not compile, because by the time it gets to TerrorAlertLevel, RED, ORANGE, YELLOW, BLUE, and GREEN are already defined, thanks to the Color enumeration. And worst off, if you have a coding standard that does not require you to have your enumerations all in caps (which makes sense, since part of the reason that Macros are usually done in caps is to discourage their use), then you could have an issue with any variables, such as int red = 0xFF0000; would not compile if the enumeration was all in lower-case.

As such, developers in C++ tend to add a prefix to the definition, such as:

  1. enum Color { COLOR_RED, COLOR_YELLOW, COLOR_ORANGE, COLOR_GREEN, COLOR_BLUE, COLOR_BROWN, COLOR_BLACK, COLOR_PURPLE };
  2. enum TerrorAlertLevel { TAL_RED, TAL_ORANGE, TAL_YELLOW, TAL_BLUE, TAL_GREEN };

Oh, that looks friendly.

Well, to help in that friendliness, C++09 is adding strongly typed enums. This is done by adding the class keyword to the enum definition. For example, the first C++ example above could compile under C++09 as this:

  1. enum class Color { RED, YELLOW, ORANGE, GREEN, BLUE, BROWN, BLACK, PURPLE };
  2. enum class TerrorAlertLevel { RED, ORANGE, YELLOW, BLUE, GREEN };

The bold emphasizes the difference.

Conceptually, I think this is a great addition to C++, making it easier to reuse enumerations and avoiding the crazy compilation errors that you can get if you accidentally name your variable a name that has already been defined in an enum.

The part that I do not like about this proposal, however, is the fact that it uses the keyword class but it is not a class. You cannot add member functions to it, which because of the power of the Java enumerations, I think this is confusing for developers which experience with Java enumerations.

C# enumerations are strongly typed but you cannot add any methods to them. But at least, they do not use the word class in their definition.

While I more than welcome the strongly-typed nature of enumerations in C++, I think that the implementation could have overloaded a better keyword than class. Since it does seem like this has been accepted already, hopefully a future version of the standard will add the ability to add member functions to the enumeration, minimizing some of this confusion.

Earlier Entries

2  3  4  5  6  >

Navigation

Recent Posts

Get Firefox
eyt*