Some Java oddities
I was recently asked for some simple pieces of code which some unusual uses of Java.
Here are some of my favourites ;)
Stateless Singleton implementing an interface
public enum RandomStrategy implements IntSupplier {
INSTANCE;
@Override
public int getAsInt() {
return ThreadLocalRandom.current().nextInt();
}
}
This is useful for creating multiple implementations of a strategy pattern which share an interface. E.g. I have TimeProvider with 4 implementations depending on usage.
An example of where I use this is a TimeProvider which is basically
@FunctionalInterface
public interface TimeProvider {
long currentTimeMillis();
default long currentTimeMicros() {
return currentTimeMillis() * 1000;
}
This has multiple enum
implementations which share an interface so they can be used interchangably
TimeProvider |
Usage |
a set time for unit testing. |
|
uses the wall clock. |
|
use wall clock except for the micro-second time always increases |
|
LinuxTimeProvider (TBD) |
Uses a microsecond resolution system call |
Almost final
static final int l = printNM();
static final int n = 10;
static final int m = Math.min(10, 10);
static final int o = printNM();
static int printNM() {
System.out.println(n + " " + m); // 10 0 then 10 10
return 5;
}
Before a variable is assigned a value it is 0
, false
or null
unless the value is known at compile time in which case it is also inlined.
Smiley faces
int ⁀‿⁀ = 0, ⁀⁔⁀ = 1, ¢ = 2;
if (⁀‿⁀ != ⁀⁔⁀)
System.out.println(¢);
As _
and $
are allowed characters so all continuation and currency symbols are allowed.
Getting the top bit whether int or long.
int i = -1;
long l = -1;
System.out.println("sign(i)=" + (i >> -1));
System.out.println("sign(l)=" + (l >> -1));
The shift value is masked by the lower 5 bit for int or 6 bits for long. The upshot is that a shift by -1 is either 31 or 63 depending on the type.
A Throwable for tracing only
/**
* Throwable created purely for the purposes of reporting a stack trace.
* <p>
* This is not an Error or an Exception and is not expected to be thrown or caught.
* </p>
*/
public class StackTrace extends Throwable {
public StackTrace() {
this(null);
}
public StackTrace(String message) {
this(message, null);
}
public StackTrace(String message, Throwable cause) {
super(message, cause, false, false);
}
}
We use this for tracing where resources are allocated and/or closed to reporting on multi-threaded resource management
No ConcurrentModificationException.
The check for iterations == size happens before the modification count for CME.
List<Integer> ints = new ArrayList<Integer>() {{
add(1);
add(2);
add(3);
}};
for (int i : ints) // no exception
if (i == 2)
ints.remove(i);
Wrapper pooling covers the range -128 to 127 for Byte
, Short
, Character
, Integer
and Long
. (Possibly higher for Integer
depending on command line options.)
Character a1 = 127, a2 = 127;
Character b1 = 128, b2 = 128;
System.out.println(a1 == a2); // true
System.out.println(b1 == b2); // false
Detected assertions are on.
boolean debug = false;
assert debug = true;
if (debug)
System.out.println("Assertions are on");
This shows you can easily determine is assertions are on for expensive checks. Another simple approach is:
public void method() {
assert validate();
}
private boolean validate() {
if (expensiveCheck())
throw new AssertionError("details");
return true;
}
Legacy arrays on methods are allowed as easier compilers allowed this.
static int fun(int[] ints)[] { return ints; }
public static void main(String... args) {
System.out.println(fun(new int[1]).length);
}
char and floating point
The compound assignment operator casts to the wider type and then narrows it implicitly.
char ch = '1';
ch /= 0.9;
System.out.println(ch);
int and float
Wider types don’t always have more precision. A float
is wider than an int
or long
, but has less precision for whole numbers inside the int and long ranges.
int i = Integer.MAX_VALUE;
i += 0.0f;
System.out.println(i == Integer.MAX_VALUE);
i -= 63;
i += 0.0f;
System.out.println(i == Integer.MAX_VALUE);
i -= 64;
i += 0.0f;
System.out.println(i == Integer.MAX_VALUE);
Unknown exit code
One of the threads in your ForkJoinPool.commonPoll()
will be the first to call exit.
IntStream.range(0, 128)
.parallel()
.forEach(System::exit);
WindowsTF
Windows treats certain file names as special devices, even if a path or file extension is provided.
C:\Users\peter>more > A.java
class Nul { }
class Con { String s = "\nHello World\n"; }
^Z
C:\Users\peter>javac A.java (1)
╩■║╛ 4
s Ljava/lang/String; <init> ()V Code LineNumberTable
SourceFile A.java
Hello World
Con java/lang/Object
# *╖ *╡ ▒
C:\Users\peter>dir
Volume in drive C is OS
Volume Serial Number is 3EB6-6BBF
Directory of C:\Users\peter
04/09/2018 13:51 <DIR> .
04/09/2018 13:51 <DIR> ..
04/09/2018 13:51 62 A.java (2)
1 File(s) 62 bytes
2 Dir(s) 670,935,572,480 bytes free
1 | Compiling the code dumps the .class to the screen. |
2 | Note: no .class files are written. |