Java: Difference between revisions

From miki
Jump to navigation Jump to search
 
(33 intermediate revisions by the same user not shown)
Line 4: Line 4:
== Links ==
== Links ==
* [http://www.javabeat.net/articles/33-generics-in-java-50-1.html Generics in Java 5.0]
* [http://www.javabeat.net/articles/33-generics-in-java-50-1.html Generics in Java 5.0]
* [http://www.tedneward.com/files/Papers/BootClasspath/BootClasspath.pdf Using the BootClassPath]


== <tt>java.exe</tt> Command-Line ==
== <tt>java.exe</tt> Command-Line ==
Line 13: Line 14:


<source lang=bash>
<source lang=bash>
java -jar myjar.jar
java -Djava.library.path=.\var -jar "$(MYROOT)\var\main.jar"
java -Djava.library.path=.\var -jar "$(MYROOT)\var\main.jar"
</source>

;<code>-encoding &lt;encoding&gt;</code>
:Set file encoding (e.g. <code>utf-8</code>, <code>iso-8859-1</code>)

;<code>-Dhttp.proxyHost=&lt;server&gt;</code>
;<code>-Dhttp.proxyPort=&lt;port&gt;</code>
;<code>-Dhttps.proxyHost=&lt;server&gt;</code>
;<code>-Dhttps.proxyPort=&lt;port&gt;</code>
;<code>-DsocksProxyHost=&lt;server&gt;</code>
;<code>-DsocksProxyPort=&lt;port&gt;</code>
Configure proxies (see [http://docs.oracle.com/javase/6/docs/technotes/guides/net/proxies.html]).
<source lang=bash>
java -Dhttp.proxyHost=localhost -Dhttp.proxyPort=80 -Dhttps.proxyHost=localhost -Dhttps.proxyPort=443 -DsocksProxyHost=localhost -DsocksProxyPort=1080 -jar myjar.jar
</source>
</source>


== Sample Program ==
== Sample Program ==
* Create a file <tt>HelloWorld.java</tt>, with content:
* Create a file <tt>HelloWorld.java</tt>, in the current directory, with content:
<source lang="java">
<source lang="java">
public class HelloWorld {
public class HelloWorld {
Line 35: Line 51:
<source lang=bash>
<source lang=bash>
java HelloWorld
java HelloWorld
</source>
=== Creating a Java archive (JAR file) ===
* Now we'll make a ''jar'' file, but let's first move files around to make a more realistic example:
<source lang=bash>
mkdir -p src/org/immie/example
mv HelloWorld.java src/org/immie/example
</source>
* Edit <tt>src/org/immie/example/HelloWorld.java</tt> to add package information:
<source lang="java">
package org.immie.example;

public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
for (int i = 0; i < args.length; i++)
System.out.print(0 == i ? args[i] : " " + args[i]);
System.out.println();
}
}
</source>
* Now we can create the ''jar'' file as follows:
<source lang=bash>
mkdir .classes
javac -cp .classes -sourcepath src -d .classes src/org/immie/example/*.java
jar cfe Hello.jar org.immie.example.HelloWorld -C .classes org/immie/example/HelloWorld.class
</source>
* Run the ''jar'' with:
<source lang=bash>
java -jar Hello.jar
</source>

== Syntax - General ==
=== Switch ===
<source lang="java">
switch( var ) { // var must be char, byte, short or int.
case 1:
System.out.println("one");
break;
case 2:
System.out.println("too");
//fall-through !!!
default:
System.out.println("many");
}
</source>

== Syntax 1.4 ==
=== String ===
<source lang=java>
String s = "Hello";
int l = s.length();
</source>

=== Arrays ===
* Index is 0-based
* Array base type can be any primitive type or reference types.
* <code>new</code> allocates room for primitive types, or for references (not for object instance themselves).
* After creation, arrays cannot grow or shrink. For dynamic arrays, consider using '''<code>ArrayList</code>''' class.

<source lang="java">
// Declaration
int [] arrayOfInts; // preferred declaration style
int arrayOfInts []; // ... c-style

// Creation and Initialization
int arrayOfInts [] = new int [42]; // declaration and creation (set to 0)
arrayOfInts[0] = 69;

String [] someStrings = new String [ 3 ]; // ... idem (set to null)
String [] someStrings = { null, null, null }; // ... same as above
String [] someStrings = { "hello", new String(), someStuff.toString(), null };

// Anonymous arrays
setPets ( new Animal [] { new Dog("gray"), new Cat("grey"), new Cat("orange") });

// Get array length
int aLen = arrayOfInts.length
</source>
* Copy array using <code>System.arraycopy</code> (from [http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html]):
<source lang=java>
char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd' };
char[] copyTo = new char[7];
System.arraycopy(copyFrom, 2, copyTo, 0, 7);
System.out.println(new String(copyTo));
</source>
</source>


== Syntax ==
== Syntax 1.5 ==


=== For loops ===
=== For loops ===
Line 94: Line 194:
printf ("Class name is %s\n",MyClass.class.getName());
printf ("Class name is %s\n",MyClass.class.getName());
</source>}}
</source>}}

;[http://www.javaworld.com/javaworld/javatips/jw-javatip124.html?page=1 Throwable.getStackTrace()]
:Could be used to get the name of current class / methods for debug...

== API ==
=== System ===
{| class=wikitable
|-
!colspan=2|Method Summary
|-
|<tt>static long</tt>
|<code>currentTimeMillis()</code>
:Returns the current time in milliseconds.
|}

== How-To ==
=== Generate a string of repeating characters ===
On Java 1.4.2:
<source lang="java">
String repeatchar(char c, int len)
{
char [] a = new char[len];
Arrays.fill(a, c);
return new String(a);
} /* repeatchar */
</source>

Other pointers:
* Check <code>java.util.Formatter</code>
* Apache StringUtils has several methods: leftPad, rightPad, center and repeat. http://www.jdocs.com/lang/2.1/org/apache/commons/lang/StringUtils.html

=== Pad a string ===
On Java 1.4.2 (see [http://www.rgagnon.com/javadetails/java-0448.html]):
<source lang="java">
public static String padString(String s, int n, char c, boolean padLeft)
{
if ( null == s ) {
return null;
}

int npad = n - s.length();
if ( npad < 0 ) {
return s;
}

char [] pad = new char [npad];
Arrays.fill(pad, c);
return ( padLeft ) ? new String(pad) + s : s + new String(pad); // TODO: Faster to use StringBuffer, and insert/append?
} /* padString */

</source>

On Java 1.5, use <code>String.format</code>:
<source lang="java">
public static String padRight(String s, int n) {
return String.format("%1$-" + n + "s", s);
}

public static String padLeft(String s, int n) {
return String.format("%1$#" + n + "s", s);
}
</source>

Other pointers:
* For formatting numbers, use <code>java.text.DecimalFormat</code> (see [http://download.oracle.com/javase/tutorial/java/data/numberformat.html])
* Since Java 1.5, one should prefer using <code>StringBuilder</code> over <code>StringBuffer</code>.
* rosettacode.org contains more code snippets for any language ([http://rosettacode.org/wiki/Repeat_a_string#Java])

===Pad a String (fixed length)====
Some nasty trick I found ;-) :
<source lang=java>
Integer.toHexString(value & 0xff | 0x100).substring(1) ); // Nasty trick to force byte padding
Integer.toHexString(value & 0xffff| 0x10000).substring(1) ); // Nasty trick to force word padding
</source>

===Get System Properties (incl. ''BootClassPath'')===

<source lang=java>
/**
* Save this class file as 'Props.java'
*/
public class Props {
public static void main (String args[]) {
try {
System.getProperties().store(System.out,"HEADER");
}
catch(Exception e) {

}
}
}
</source>

Compile and run with:
<source lang=bash>
javac Props.java
java Props
</source>

== Patterns ==
=== Singleton ===
* [http://javarevisited.blogspot.com/2011/03/10-interview-questions-on-singleton.html 10 Interview questions on Singleton Pattern in Java]
* [http://java.sun.com/developer/technicalArticles/Programming/singletons/ When is a Singleton not a Singleton?]
* [http://www.javabeginner.com/learn-java/java-singleton-design-pattern Java Singleton Design Pattern]
* [http://radio-weblogs.com/0122027/stories/2003/10/20/implementingTheSingletonPatternInJava.html Implementing the Singleton Pattern in Java]
* [http://java.sun.com/docs/books/effective/ Effective Java]

A ''Singleton'' is a design pattern that guarantees that there can be at most one instance of a given class in a VM. The objective is controlling object creation, in this case limiting it to one.

Advantage of ''Singleton'' over a class with only static members:
* Static methods cannot implements an interface. Singleton can be used to implements an interface (&rarr; very handy for Provider frameworks).
* Static methods cannot be overridden (aka. they are de-facto ''final'').
* it is not difficult to initialize the Singleton based on run-time information.

Remember that the main objective of singleton is to limit instance of created objects. So there is nothing inherently bad at referring to static members in public methods of the Singleton, as long as these members remains private.

'''Frequent caveats''':
* Multi-instance because lack of synchronization in multi-threaded environment.
:The best solution is to rely on static initialization. In that case, object is created as soon as class is referenced or needed.
<source lang="java">
// Normal static initialization (not lazy)
private static final Foo foo = new Foo();
public static Foo getFoo() {
return foo;
}
</source>
:Using the ''initialize-on-demand holder class'' is only useful is there are cases where one would refer to the class but not uses the singleton. For instance, the <tt>System</tt> class has several singletons, but one rarely needs them all at once, and so it makes sense to only create them on demand. If that's not the case, rely on static initialization.

=== Synchronization ===
(from Tim's doc, TLMT-DocumentingAPIsynchronizationproperties-070313-0948-6.pdf, and effective Java)
* Do not add the qualifier <code>synchronized</code> to your method signature. Adding the qualifier will make the method call synchronize on your Object's lock. This lock is publicly accessible and synchronized applications might be tempted to use the lock in unexpected ways leading to deadlock. Synchronization locks should always be
internal to your application. Use private objects for your locks.
* Do not call listener callbacks in synchronized region or while holding a lock because this may lead to deadlock situations or performance problems (see ''Effective Java'').
* If your API offers a listener to notify of state changes, call the listener immediately on first registration to notify the client of the current state at registration time. This avoids the application to call <code>getState</code> method, which would require lots of synchronization code (ugly, complex).

== Debug ==
;References
* http://blog.zvikico.com/2007/11/five-ways-for-t.html

Logging:
* http://java.sun.com/j2se/1.4.2/docs/guide/util/logging/
* http://commons.apache.org/logging/
* http://logging.apache.org/log4j/1.2/index.html

Dynamic Proxy:
* http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html

;Java Trace
* cfr [http://download.oracle.com/javase/1.5.0/docs/guide/jpda/trace.html]

;Profilers
* http://www.eclipse.org/tptp/

;Aspect-Oriented Programming:
* http://en.wikipedia.org/wiki/Aspect-oriented_programming


Some sample code:
<source lang="java">
private static final String ANSI_PURPLE = (char) 27 + "[35m";
private static final String ANSI_NONE = (char) 27 + "[0m";

public static String getMethodName()
{
return getMethodName(1);
}

public static String getMethodName(int idx)
{
return new Throwable().getStackTrace()[1].getMethodName();
}

public static String getFileMethodLine()
{
return getFileMethodLine(1);
}

public static String getFileMethodLine(int idx)
{
StackTraceElement e = new Throwable().getStackTrace()[idx];

//return e.getClassName() + "." + e.getMethodName() + "(" + e.getFileName() + ":" + e.getLineNumber() + ")"; // Java like
return e.getFileName() + " " + e.getMethodName() + ":" + e.getLineNumber(); // C like
}

public static void debug(String s)
{
System.out.println(ANSI_PURPLE + getFileMethodLine(2) + ANSI_NONE + " " + s);
}
</source>


== References ==
== References ==
* [http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java Convert a string representation of a hex dump to a byte array using Java?]
<source lang=java>
<source lang=java>
String Integer.toHexString(byte); // Convert an integer to string in hexadecimal
String Integer.toHexString(byte); // Convert an integer to string in hexadecimal
Line 113: Line 404:
System.out.print((hex.length()>1? "" : "0") + hex + ", ");
System.out.print((hex.length()>1? "" : "0") + hex + ", ");


//Prepend 0 if needed (unsigned byte)
System.out.print((aInt<16? "" : "0") + Integer.toHexString(aInt) + ", ");

//Prepent 0 if needed (unsigned byte - using faster StringBuffer)
StringBuffer hexbuf = new StringBuffer();
if (aInt < 16) hexbuf.append('0');
hexbuf.append(Integer.toHexString(aInt));
</source>
</source>

<source lang=java>
/**
* Convert a byte array into hexadecimal string, prefixing each byte with '0x'.
*
* @param data byte array to convert
* @return String of hexadecimal bytes.
*/
static public String toHexString0x(byte[] data)
{
StringBuffer buf = new StringBuffer();
for ( int i = 0; i < data.length; i++ ) {
int a = data[i] & 0xff;
buf.append(a < 16 ? "0x0" : "0x");
buf.append( Integer.toHexString(a) );
buf.append(' ');
}
return buf.toString();
} /* toHexString0x */

/**
* Convert a byte array into hexadecimal string, where bytes are grouped by 4 separated by a single space.
*
* @param data byte array to convert
* @return String of hexadecimal bytes.
*/
static public String toHexStringCompact(byte[] data)
{
StringBuffer buf = new StringBuffer();
for ( int i = 0; i < data.length; i++ ) {
int a = data[i] & 0xff;
if ( a < 16 ) {
buf.append('0');
}
buf.append( Integer.toHexString(a) );
if ( 3 == (i & 3) ) {
buf.append(' ');
}
}
return buf.toString();
} /* toHexStringCompact */


// Convert an hexadecimal string into array of byte (assume sane input)
// input validity can be tested with:
// url.matches("^//(\p{XDigit}\p{XDigit})+$")
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}

// Convert an hexadecimal string into array of byte (unsafe input)
public static byte[] hexStringToByteArray(String s) {
int lsd, msd;
int len = s.length();

if ( 0 != len & 1 ) {
throw new IllegalArgumentException();
}
byte[] data = new byte[len / 2];
for ( int i = 0; i < len; i += 2 ) {
msd = Character.digit(s.charAt(i), 16);
lsd = Character.digit(s.charAt(i + 1), 16);
if ( 0 > msd || 0 > lsd ) {
throw new IllegalArgumentException();
}
data[i / 2] = (byte) ( (msd << 4) + lsd );
}
return data;
}
</source>

== JUnit ==
* [http://www.vogella.com/articles/JUnit/article.html JUnit - Tutorial at vogella.com]
* [http://java.syntaxerrors.info/index.php?title=Junit.framework.AssertionFailedError:_No_tests_found_in_a.b.c.FooTest Junit.framework.AssertionFailedError: No tests found in a.b.c.FooTest]

Skeleton test class:
<source lang=java>
package com.nxp.TDD;

import com.nxp.TDD.Money; // The class to test
import org.junit.Test;
import junit.framework.TestCase;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class MoneyTest extends TestCase { // Test class must extend TestCase
@Test // Don't forget (junit4) !
public void testEquality() {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
}
</source>

Notes:
* Test can be run with (assuming that all application and test classes are in <tt>main.jar</tt>):
<source lang=bash>
java -cp /usr/share/java/junit4.jar:main.jar org.junit.runner.JUnitCore com.nxp.TDD.MoneyTest
# or using junit executable
CLASSPATH=main.jar junit -text com.nxp.TDD.MoneyTest
# or using junit executable - swing GUI
CLASSPATH=main.jar junit -swing # enter "com.nxp.TDD.MoneyTest" in Test class name
</source>
* When using ''junit'' executable, test class must extends <code>junit.framework.TestCase</code> or junit will return this error message:
<source lang=text>
$ junit -text com.nxp.TDD.MoneyTest

There was 1 failure:
1) warning(junit.framework.TestSuite$1)junit.framework.AssertionFailedError: No tests found in com.nxp.TDD.MoneyTest
</source>
* Strangely this is not necessary when calling <code>java org.junit.runner.JUnitCore ...</code>

== Java Decompiler ==
Use [http://jd.benow.ca/ JD Project], free and available under Linux as well.

Latest revision as of 01:14, 23 December 2013

Other pages

Links

java.exe Command-Line

-Djava.library.path=<dllpath>
Set path to find DLL Libraries
-jar <jarfile>
Set jar file to load (should contain main())
java -jar myjar.jar
java -Djava.library.path=.\var -jar "$(MYROOT)\var\main.jar"
-encoding <encoding>
Set file encoding (e.g. utf-8, iso-8859-1)
-Dhttp.proxyHost=<server>
-Dhttp.proxyPort=<port>
-Dhttps.proxyHost=<server>
-Dhttps.proxyPort=<port>
-DsocksProxyHost=<server>
-DsocksProxyPort=<port>

Configure proxies (see [1]).

java -Dhttp.proxyHost=localhost -Dhttp.proxyPort=80 -Dhttps.proxyHost=localhost -Dhttps.proxyPort=443 -DsocksProxyHost=localhost -DsocksProxyPort=1080 -jar myjar.jar

Sample Program

  • Create a file HelloWorld.java, in the current directory, with content:
public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, World!");
    for (int i = 0; i < args.length; i++)
      System.out.print(0 == i ? args[i] : " " + args[i]);
    System.out.println();
  }
}
  • Compile (javac must be in the path):
javac HelloWorld.java
  • Run:
java HelloWorld

Creating a Java archive (JAR file)

  • Now we'll make a jar file, but let's first move files around to make a more realistic example:
mkdir -p src/org/immie/example
mv HelloWorld.java src/org/immie/example
  • Edit src/org/immie/example/HelloWorld.java to add package information:
package org.immie.example;

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, World!");
    for (int i = 0; i < args.length; i++)
      System.out.print(0 == i ? args[i] : " " + args[i]);
    System.out.println();
  }
}
  • Now we can create the jar file as follows:
mkdir .classes
javac -cp .classes -sourcepath src -d .classes src/org/immie/example/*.java
jar cfe Hello.jar org.immie.example.HelloWorld -C .classes org/immie/example/HelloWorld.class
  • Run the jar with:
java -jar Hello.jar

Syntax - General

Switch

switch( var ) {                    // var must be char, byte, short or int.
  case 1: 
    System.out.println("one");
    break;
  case 2: 
    System.out.println("too");
    //fall-through !!!
  default: 
    System.out.println("many");
}

Syntax 1.4

String

String s = "Hello";
int l = s.length();

Arrays

  • Index is 0-based
  • Array base type can be any primitive type or reference types.
  • new allocates room for primitive types, or for references (not for object instance themselves).
  • After creation, arrays cannot grow or shrink. For dynamic arrays, consider using ArrayList class.
// Declaration
int [] arrayOfInts;                                // preferred declaration style
int arrayOfInts [];                                // ... c-style

// Creation and Initialization
int arrayOfInts [] = new int [42];                 // declaration and creation (set to 0)
arrayOfInts[0] = 69;

String [] someStrings = new String [ 3 ];          // ... idem (set to null)
String [] someStrings = { null, null, null };      // ... same as above
String [] someStrings = { "hello", new String(), someStuff.toString(), null };

// Anonymous arrays
setPets ( new Animal [] { new Dog("gray"), new Cat("grey"), new Cat("orange") });

// Get array length
int aLen = arrayOfInts.length
  • Copy array using System.arraycopy (from [2]):
char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd' };
char[] copyTo = new char[7];
System.arraycopy(copyFrom, 2, copyTo, 0, 7);
System.out.println(new String(copyTo));

Syntax 1.5

For loops

Foreach loops (available since 1.5) [3]:

  • More readable
  • Series of values
  • Arrays and Collections
  • Applies to Iterable<E>.

But

  • Only access.
  • Only single structure.
  • Only single element.
  • Only forward.
  • At least Java 5.
FOR EACH loop Equivalent FOR loop
for (type var : arr) {
    body-of-loop
}
for (int i = 0; i < arr.length; i++) { 
    type var = arr[i];
    body-of-loop
}
for (type var : coll) {
    body-of-loop
}
for (Iterator<type> iter = coll.iterator(); iter.hasNext(); ) {
    type var = iter.next();
    body-of-loop
}

Miscellaneous

Class Literal
A class literal is an expression consisting of the name of a class, interface, array, or primitive type followed by a . and the token class. The type of a class literal is Class. It evaluates to the Class object for the named type (or for void) as defined by the defining class loader of the class of the current instance.
Eg:
public class MyClass //...
//...
printf ("Class name is %s\n",MyClass.class.getName());
Throwable.getStackTrace()
Could be used to get the name of current class / methods for debug...

API

System

Method Summary
static long currentTimeMillis()
Returns the current time in milliseconds.

How-To

Generate a string of repeating characters

On Java 1.4.2:

  String repeatchar(char c, int len)
  {
    char [] a = new char[len];
    Arrays.fill(a, c);
    return new String(a);
  } /* repeatchar */

Other pointers:

Pad a string

On Java 1.4.2 (see [4]):

  public static String padString(String s, int n, char c, boolean padLeft)
  {
    if ( null == s ) {
      return null;
    }

    int  npad = n - s.length();
    if ( npad < 0 ) {
      return s;
    }

    char [] pad = new char [npad];
    Arrays.fill(pad, c);
    return ( padLeft ) ? new String(pad) + s : s + new String(pad);  // TODO: Faster to use StringBuffer, and insert/append?
  } /* padString */

On Java 1.5, use String.format:

public static String padRight(String s, int n) {
     return String.format("%1$-" + n + "s", s);  
}

public static String padLeft(String s, int n) {
    return String.format("%1$#" + n + "s", s);  
}

Other pointers:

  • For formatting numbers, use java.text.DecimalFormat (see [5])
  • Since Java 1.5, one should prefer using StringBuilder over StringBuffer.
  • rosettacode.org contains more code snippets for any language ([6])

Pad a String (fixed length)=

Some nasty trick I found ;-) :

  Integer.toHexString(value & 0xff | 0x100).substring(1) );    // Nasty trick to force byte padding
  Integer.toHexString(value & 0xffff| 0x10000).substring(1) );  // Nasty trick to force word padding

Get System Properties (incl. BootClassPath)

/**
 * Save this class file as 'Props.java'
 */
public class Props {
    public static void main (String args[]) {
        try {
            System.getProperties().store(System.out,"HEADER");
        }
        catch(Exception e) {

        }
    }
}

Compile and run with:

javac Props.java
java Props

Patterns

Singleton

A Singleton is a design pattern that guarantees that there can be at most one instance of a given class in a VM. The objective is controlling object creation, in this case limiting it to one.

Advantage of Singleton over a class with only static members:

  • Static methods cannot implements an interface. Singleton can be used to implements an interface (→ very handy for Provider frameworks).
  • Static methods cannot be overridden (aka. they are de-facto final).
  • it is not difficult to initialize the Singleton based on run-time information.

Remember that the main objective of singleton is to limit instance of created objects. So there is nothing inherently bad at referring to static members in public methods of the Singleton, as long as these members remains private.

Frequent caveats:

  • Multi-instance because lack of synchronization in multi-threaded environment.
The best solution is to rely on static initialization. In that case, object is created as soon as class is referenced or needed.
// Normal static initialization (not lazy)
private static final Foo foo = new Foo(); 
public static Foo getFoo() { 
    return foo; 
}
Using the initialize-on-demand holder class is only useful is there are cases where one would refer to the class but not uses the singleton. For instance, the System class has several singletons, but one rarely needs them all at once, and so it makes sense to only create them on demand. If that's not the case, rely on static initialization.

Synchronization

(from Tim's doc, TLMT-DocumentingAPIsynchronizationproperties-070313-0948-6.pdf, and effective Java)

  • Do not add the qualifier synchronized to your method signature. Adding the qualifier will make the method call synchronize on your Object's lock. This lock is publicly accessible and synchronized applications might be tempted to use the lock in unexpected ways leading to deadlock. Synchronization locks should always be

internal to your application. Use private objects for your locks.

  • Do not call listener callbacks in synchronized region or while holding a lock because this may lead to deadlock situations or performance problems (see Effective Java).
  • If your API offers a listener to notify of state changes, call the listener immediately on first registration to notify the client of the current state at registration time. This avoids the application to call getState method, which would require lots of synchronization code (ugly, complex).

Debug

References

Logging:

Dynamic Proxy:

Java Trace
Profilers
Aspect-Oriented Programming


Some sample code:

  private static final String ANSI_PURPLE = (char) 27 + "[35m";
  private static final String ANSI_NONE   = (char) 27 + "[0m";

  public static String getMethodName()
  {
    return getMethodName(1);
  }

  public static String getMethodName(int idx)
  {
    return new Throwable().getStackTrace()[1].getMethodName();
  }

  public static String getFileMethodLine()
  {
    return getFileMethodLine(1);
  }

  public static String getFileMethodLine(int idx)
  {
    StackTraceElement e = new Throwable().getStackTrace()[idx];

    //return e.getClassName() + "." + e.getMethodName() + "(" + e.getFileName() + ":" + e.getLineNumber() + ")";    // Java like
    return e.getFileName() + " " + e.getMethodName() + ":" + e.getLineNumber();                                   // C like
  }

  public static void debug(String s)
  {
    System.out.println(ANSI_PURPLE + getFileMethodLine(2) + ANSI_NONE + " " + s);
  }

References

String Integer.toHexString(byte);                    // Convert an integer to string in hexadecimal

"00" + Integer.toHexString( i )                      // Pad with leading zeros (then take rightmost characters)

String.format("%04x",0x2a);

//Prepend 0 if needed
String hex = Integer.toHexString(abyte & 0xff);
StringBuffer hexbuf = new StringBuffer();
if (hex.length() == 1) hexbuf.append('0');
hexbuf.append(hex);

//Prepend 0 if needed
String hex=Integer.toHexString(aInt);                  // Assume 0<= aInt <= 255 (i.e. positive!)
System.out.print((hex.length()>1? "" : "0") + hex + ", ");

//Prepend 0 if needed (unsigned byte)
System.out.print((aInt<16? "" : "0") + Integer.toHexString(aInt) + ", ");

//Prepent 0 if needed (unsigned byte - using faster StringBuffer)
StringBuffer hexbuf = new StringBuffer();
if (aInt < 16) hexbuf.append('0');
hexbuf.append(Integer.toHexString(aInt));
/**
 * Convert a byte array into hexadecimal string, prefixing each byte with '0x'.
 *
 * @param data   byte array to convert
 * @return       String of hexadecimal bytes.
 */
static public String toHexString0x(byte[] data)
{
  StringBuffer  buf = new StringBuffer();
  for ( int i = 0; i < data.length; i++ ) {
    int  a = data[i] & 0xff;
    buf.append(a < 16 ? "0x0" : "0x");
    buf.append( Integer.toHexString(a) );
    buf.append(' ');
  }
  return buf.toString();
} /* toHexString0x */

/**
 * Convert a byte array into hexadecimal string, where bytes are grouped by 4 separated by a single space.
 *
 * @param data   byte array to convert
 * @return       String of hexadecimal bytes.
 */
static public String toHexStringCompact(byte[] data)
{
  StringBuffer  buf = new StringBuffer();
  for ( int i = 0; i < data.length; i++ ) {
    int  a = data[i] & 0xff;
    if ( a < 16 ) {
      buf.append('0');
    }
    buf.append( Integer.toHexString(a) );
    if ( 3 == (i & 3) ) {
      buf.append(' ');
    }
  }
  return buf.toString();
} /* toHexStringCompact */


// Convert an hexadecimal string into array of byte (assume sane input)
// input validity can be tested with:
//   url.matches("^//(\p{XDigit}\p{XDigit})+$")
public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

// Convert an hexadecimal string into array of byte (unsafe input)
public static byte[] hexStringToByteArray(String s) {
    int  lsd, msd;
    int  len = s.length();

    if ( 0 != len & 1 ) {
        throw new IllegalArgumentException();
    }
    byte[] data = new byte[len / 2];
    for ( int i = 0; i < len; i += 2 ) {
        msd = Character.digit(s.charAt(i), 16);
        lsd = Character.digit(s.charAt(i + 1), 16);
        if ( 0 > msd || 0 > lsd ) {
            throw new IllegalArgumentException();
        }
        data[i / 2] = (byte) ( (msd << 4) + lsd );
    }
    return data;
}

JUnit

Skeleton test class:

package com.nxp.TDD;

import com.nxp.TDD.Money;                                 // The class to test
import org.junit.Test;
import junit.framework.TestCase;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class MoneyTest extends TestCase {                 // Test class must extend TestCase
  @Test                                                    // Don't forget (junit4) !
  public void testEquality() {
    assertTrue(Money.dollar(5).equals(Money.dollar(5)));
    assertFalse(Money.dollar(5).equals(Money.dollar(6)));
    assertFalse(Money.franc(5).equals(Money.dollar(5)));
  }
}

Notes:

  • Test can be run with (assuming that all application and test classes are in main.jar):
java -cp /usr/share/java/junit4.jar:main.jar org.junit.runner.JUnitCore com.nxp.TDD.MoneyTest
# or using junit executable
CLASSPATH=main.jar junit -text com.nxp.TDD.MoneyTest
# or using junit executable - swing GUI
CLASSPATH=main.jar junit -swing                       # enter "com.nxp.TDD.MoneyTest" in Test class name
  • When using junit executable, test class must extends junit.framework.TestCase or junit will return this error message:
$ junit -text com.nxp.TDD.MoneyTest

There was 1 failure:
1) warning(junit.framework.TestSuite$1)junit.framework.AssertionFailedError: No tests found in com.nxp.TDD.MoneyTest
  • Strangely this is not necessary when calling java org.junit.runner.JUnitCore ...

Java Decompiler

Use JD Project, free and available under Linux as well.