Archive for the ‘Java’ Category
Why you should NOT use log.isDebugEnabled()
Several people are telling you that you should wrap all logging statements by a isXXXEnabled method call (where XXX is the logging level) to prevent unecessary object creations. I do not recomment this!
-It’s not part of your business logic but a kind of optimization
-The code becomes less readable
-When you change the loglevel you also have to change the isXXXEnabled call (error prune)
-…and at least: This is a very boring job
Boring job!? Why don’t let some optimizer do this work for us!? And here comes http://sourceforge.net/projects/just4log/files/
This project comes with and AntTask adding the “missing” statements for us:
a();
logger.debug(“Got ” + input + “, will return ” + output);
b();
becomes
a();
if (logger.isDebugEnabled())
logger.debug(“Got ” + input + “, will return ” + output);
b();
Didn’t I say the isXXXEnabled statements are not needed? No! I didn’t! They are very very useful. I just said that they shouldn’t be written by the programmer itself.
Oh! The project is dead since 6 years, see forum (http://sourceforge.net/projects/just4log/forums/forum/288112/topic/1354439)
Because of that and that the project did not support SLF4J (Simple Logging Fascade for Java) I decided to relaunch the whole project: Tataaaaa, here it is: http://sourceforge.net/projects/just4log-ng/
You might say: “Hey! You don’t have to check the loglevel using SLF4J!”. Unfortunately this is not the truth:
Of couse you can use the parameterized messages SLF4J is supporting
logger.debug(“The new entry is {}.”, entry);
but if you’d like to log more than two arguments you have to use the vararg method which will create an Object[] holding your parameters (this is done automatically by the compiler). Another thing is autoboxing of primitive values:
int a=5, b=7, c=a+b;
logger.debug(“Sum of {} and {} is {}.”, sum, a, b);
What will happen here? The compiler will transform this under the hood into:
logger.debug(“Sum of {} and {} is {}.”, new Object[] { Integer.valueOf(sum), Integer.valueOf(a), Integer.valueOf(b) });
So there are 4 objects created you won’t see in your source code (3 Integers and one Object[])
Let me repeat myself: The code should be wrapped by isXXXEnabled to prevent the Object[] creation.
I recommited the code found in the old repository and did a lot of optimizations (general rework, Java5 migration, command line support, fixed some bugs)
Standard Java collections are not thread-safe
As I worked for years now in different projects I experienced that many Java programmers think it’s enough to synchronize methods modifying the state of a Collection (put, add, remove, …).I guess they think that an access method (like get) is not affected.
This is a common mistake! If you have concurrent modifying access to collections you have either to synchronize all methods accessing the collection or to use a collection which is designed for this purpose (see java.util.concurrent or Collections.synchronized… if you are using a JDK version < 5).
A small example to illustrate this:
import java.util.HashMap;
import java.util.Map;
import java.util.Random;public class StandardCollectionsAreNOTThreadSafe {
@SuppressWarnings(“nls”)
public static void main(String[] args) {
final Random random = new Random(System.currentTimeMillis());
final Map<String, Integer> m = new HashMap<String, Integer>();
Integer expected = Integer.valueOf(4711);
m.put(“foo”, expected);
new Thread() {
@Override
public void run() {
for (;;) {
int nextInt = random.nextInt();
m.put(String.valueOf(nextInt), Integer.valueOf(nextInt));
}}
}.start();for (;;) {
Integer actual = m.get(“foo”);
if (actual != expected) {
throw new RuntimeException(“Got ” + actual + ” (map size is ” + m.size() + “)”);
}}
}}
The code puts the value 4711 for key “foo” and continously retrieves the value for key “foo” from the Map while another thread puts dummy data to it. If the value retrieved from the map is not 4711 the method will throw an Exception.
Copy & compile this code if you are sure that java’s standard collections (like HashMap/ArrayList/…) are thread-safe.
Do not ignore IOException when calling close on Outputstreams/Writers
As a good Java Programmer you should close your resources in a finally block, most programmers do so.
But what you can see very often is that the close-call is surrounded by a catch block catching IOExceptions and irgnoring them, e.g.
OutputStream os = …
try {
while (…) {
os.write(…);
}
} finally {
try {
os.close();
} catch (IOException e) { /* ignore it */ }}
What’s wrong with that code?
When getting the Outputstream/Writer as argument (or even explicitly intantiating your own) you have most of the time a BufferedOutputStream/BufferedWriter. These classes write the data to the underlying Stream/Writer if their buffers are filled or flush() or close() is called on them.
That means that the remaining data in the buffer would be written when calling flush()/close().
So in the example above you’d have a corrupted file wothout noticing it.
So what’s the solution? You should never catch and ignore IOExceptions when writing to resources because they indicate that your file does not contain all the data you intended to write to it.
Java command line argument processing
A nice way to process command line arguments is arg4j (https://args4j.dev.java.net/).
The resulting code will be 10 times better than code using Apache Commons CLI (never use Findbugs/PMD or any other static software analyse tool on Commons CLI and never, really never take a look at the sources! :-/).
Example code and description can be found here. http://weblogs.java.net/blog/kohsuke/archive/2005/05/parsing_command.html
Arg4J takes full use of and supports Java5 language features (annotations and enums)
public final class Main {
public static void main(String[] args) throws CmdLineException {
new Main().doMain(args);
}@Option(name = “-h”, aliases = { “-help” }, usage = “print this message”)
private boolean help = false;@Option(name = “-i”, required = true, usage = “input from this file”, metaVar = “/path/to/your.class”)
private File in = new File(“.”);@Option(name = “-o”, required = true, usage = “output to this dir”, metaVar = “/tmp/bin”)
private File out = new File(“.”);[...]
Parsing is done easily by invoking the Parser:
private void doMain(String[] args) throws CmdLineException {
CmdLineParser parser = new CmdLineParser(this);
parser.setUsageWidth(130);
try {
parser.parseArgument(args);
} catch (CmdLineException e) {
System.err.println(e.getMessage());
showHelpAndExit(parser);
}
Calculate the Date n workings days ahead using Java
A little Java Snippet: Calculate the Date n workings days ahead:
/**
* Returns a new Date that is <code>workingDays</code> working days in the
* future based on <code>start</code>.
*
* @param start the base date
* @param workingDays count of working days
* @return newly created Date that is <code>workingDays</code> working days
* in the future based on <code>start</code>
*/
public static Date addWorkingDays(Date start, int workingDays) {
Calendar cal = Calendar.getInstance();
cal.setTime(start);
int base = workingDays + (cal.get(Calendar.DAY_OF_WEEK) – cal.get(Calendar.DAY_OF_MONTH) + 32) % 7;
cal.add(Calendar.DAY_OF_MONTH, base – 7 + (base + 4) / 5 * 2);
return cal.getTime();
}