Posts

Why double Still Outperforms BigDecimal: A Decade-Long Performance Comparison

Overview Many developers consider BigDecimal the go-to solution for handling money in Java. They often claim that by replacing double with BigDecimal , they have fixed one or more bugs in their applications. However, I find this reasoning unconvincing. It's possible that the issue lies not with double , but rather with the way it was being handled. Additionally, BigDecimal introduces significant overhead that may not justify its use. When asked to improve the performance of a financial application, I know that if BigDecimal is involved, it will eventually need to be removed. While it may not be the largest performance bottleneck initially, as we optimize the system, BigDecimal often becomes one of the main culprits. BigDecimal is not an improvement BigDecimal comes with several drawbacks. Here's a quick list of some of its key issues: It has an unnatural syntax. It uses more memory. It creates more garbage (i.e., it causes more frequent garbage colle

Uncomparable Puzzles in Java

Here are a few puzzles for you to solve in Java. The source is available here Try running the following code to reproduce the output below. See if you can work out why these results occur: long a = (1L << 54) + 1; double b = a; System.out.println("b == a is " + (b == a)); System.out.println("(long) b < a is " + ((long) b < a)); double c = 1e19; long d = 0; d += c; System.out.println("\nd < c is " + (d < c)); System.out.println("d < (long) c is " + (d < (long) c)); Double e = 0.0; Double f = 0.0; System.out.println("\ne <= f is " + (e <= f)); System.out.println("e >= f is " + (e >= f)); System.out.println("e == f is " + (e == f)); BigDecimal x = new BigDecimal("0.0"); BigDecimal y = BigDecimal.ZERO; System.out.println("\nx == y is " + (x == y)); System.out.println("x.doubleValue() == y.doubleValue() is " + (x.doubleValue() == y.doub

Ten Java Myths and Misconceptions

Advanced Java Questions These questions delve into Java's more intricate behaviors and are often too advanced for typical interviews, as they might be discouraging for candidates. However, they are excellent for deepening your understanding of Java's core workings in your own time. Myth 1: System.exit(0) Prevents finally Block Execution Consider the following code: // many frameworks have a SecurityManager System.setSecurityManager(new SecurityManager() { @Override public void checkExit(int status) { throw new ThreadDeath(); } }); try { System.exit(0); } finally { System.out.println("In the finally block"); } This code will output: In the finally block Explanation: The System.exit(0) call triggers the checkExit method in the custom SecurityManager . By throwing a ThreadDeath exception instead of terminating, the finally block is allowed to execute, explaining the "In the finally block" output. Since ThreadDea

Java Arrays, Wat!

Java Arrays: Surprising Behaviors Arrays in Java can behave in unexpected ways. Let's explore a few quirks. Is it an Array or Not? Consider the following declaration: Serializable array = new Serializable[9]; Is array an array or a scalar? In fact, it’s a scalar reference that points to an array. Similarly: Object o = new Object[9]; Here, you can assign an array to an Object variable because arrays are also objects in Java. Additionally, arrays are Serializable , so they can be assigned to a Serializable reference as well. Where Did My [] Go? Java syntax can produce some surprising results due to backward compatibility. Consider this method signature: public static int method(int[]... args)[] { return args[0]; } In this example: args is of type int[][] . The return type is int[] , indicated by the [] after the method declaration. This syntax isn’t part of the Java Language Specification (JLS); it’s allowed in OpenJDK for backward compatibility. Wh

Some Common Java Gotchas

Overview Java is a streamlined language with fewer features than others, yet it still has quirks that can confuse developers. Familiarity with other languages may lead to misinterpretation of Java syntax, often causing misunderstandings. Variables are References or Primitives, Not Objects In Java, variables represent references (for objects) or primitives, not the objects themselves. For example: String s = "Hello"; This makes s a reference to a String , not the String itself. Example Misunderstanding: Q: If String is immutable, how can I change it, like in s += "!" ? A: You’re creating a new String and updating the reference, not altering the original String . Compares References, Not Object Content Using == compares references, not object contents. For immutable values, Java may optimize by pooling them, which can make the references equal: String s1 = "Hi", s2 = "Hi"; Integer

Java is Very Fast, If You Don’t Create Many Objects

Image
  You still have to watch how many objects you create. This article looks at a benchmark passing events over TCP/IP at 4 billion events per minute using the net.openhft.chronicle.wire.channel package in Chronicle Wire and why we still avoid object allocations..  One of the key optimisations is creating almost no garbage. Allocation is a very cheap operation and collection of very short-lived objects is also very cheap. Does this really make a difference? What difference does one small object per event (44 bytes) make to the performance in a throughput test where GC pauses are amortised? While allocation is as efficient as possible, it doesn’t avoid the memory pressure on the L1/L2 caches of your CPUs and when many cores are busy, they are contending for memory in the shared L3 cache.  Results Benchmark on a Ryzen 5950X with Ubuntu 22.10. JVM Vendor, Version No objects Throughput, Average Latency* One object per event Throughput, Average Latency* Azul Zulu 1.8.0_322 60.6 M event/s, 528

Comparing Approaches to Durability in Low Latency Messaging Queues

Image
  A significant feature of Chronicle Queue Enterprise is support for TCP replication across multiple servers to ensure the high availability of application infrastructure. I generally believe that replicating data to a secondary system is faster than syncing to disk, assuming the round trip network delay wasn’t high due to quality networks and co-located redundant servers. This is the first time I have benchmarked it with a realistic example. Little’s Law and Why Latency Matters In many cases, the assumption is that the latency won't be a problem as long as throughput is high enough. However, latency is often a key factor in why the throughput isn’t high enough. Little’s law states, “ the long-term average number  L  of customers in a  stationary  system is equal to the long-term average effective arrival rate  λ  multiplied by the average time  W  that a customer spends in the system”. In computer terminology, the level of concurrency or parallelism a system has to support must be