Posts

Showing posts from 2024

How to avoid using a Triple Cast

OMG: Using a Triple Cast We've all faced situations where a seemingly simple task spirals into unexpected complexity. In 2010, I encountered such a scenario and ended up writing a triple cast! 😅 The challenge: I needed a method that would return the default value for a given type. Here's the first approach I wrote at the time: public static <T> T defaultValue(Class<T> clazz) { if (clazz == byte.class) return (T) (Byte) (byte) 0; // Other primitive types handled... return null; } Yes, this is casting madness! Let’s break it down: (byte) 0 : Initializes the default value for the byte primitive type. (Byte) : Wraps the primitive into its wrapper type, Byte . (T) : Casts it to the generic type T . While functional, this approach is overly verbose, difficult to read, and frankly, not very elegant. So, I decided to refactor it into something cleaner and more effici

Calculating an Average Without Overflow: Rounding Methods

Calculating the midpoint between two integers may seem trivial, but the naive approach can lead to overflow errors. Code sample MidpointCalculator available here The classic midpoint formula: int m = (h + l) / 2; is prone to overflow if h and l are large, causing the result to be incorrect. This bug appears in many algorithms, including binary search implementations. Understanding the Problem of Overflow In Java, the int type has a fixed range from -2,147,483,648 to 2,147,483,647 . If h and l are large, their sum might exceed this range, leading to overflow. When overflow occurs, Java wraps the result around to the negative range without warning, causing unpredictable results. Safer Approaches to Calculate a Midpoint Using a Safer Formula A well-known alternative to avoid overflow is: int m = l + (h - l) / 2; Here, we compute the difference (h - l) before dividing by 2, ensuring

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