The most annoying Java related questions

Below is my personal list of most annoying Java related questions, answers for which I found difficult to memorize, or I perceived as strange or non-intuitive when I asked them myself.

I am making this list to save on googling time and to peek occasionally on the below examples, hoping it will spark a deeper understanding of Java concepts. After time some of these things are no longer annoying or puzzling as more and more understanding of Java came in, but I keep the for record to remind myself, that "a penny saved is a penny gained".

1. How are things passed to functions?

This is one of the first questions I ask myself when looking into new language. In Java things are passed to function as a copy of their values. Let us see this in few examples:

  • in case of primitive types (boolean, byte , char , short , int , long , float and double) -
    you can do anything with them inside the function and you will not change the original variable since a function receives a copy of a value of original variable:

    public class TestClass {
        public void run() {
            int a = 0;
            System.out.println(a); //output = 0
            foo(a);
            System.out.println(a); //output = 0
    
        }
        private void foo(int a) {
            int b = 1;
            a = b; //value copy is modified, not the original value
            System.out.println(a); //output = 1
        }
    
    }
  • objects - a copy of value of a reference to the object is passed; so in a method there is an access to the memory where the object is stored; in case of:

    • mutable objects their content can be modified from within the function like below:
    public class TestClass {
        public void run() {
            //mutable Integer class
            AtomicInteger a = new AtomicInteger(0);
            System.out.println(a); //output = 0
            foo(a);
            System.out.println(a); //output = 1
    
        }
    
        private void foo(AtomicInteger a) {
            a.addAndGet(1); //object referenced by 'a' gets mutated
            System.out.println(a); //output = 1
        }
    }
    • immutable objects - their content is not modified, since they cannot be mutated; when doing a++ below, actually the new Integer object somewhere in memory is created and a reference to it is assigned to a. But this foo originating a is a separate copy of run originating a, so foo's a is changed, and run's a is untouched;
    public class TestClass {
    
        public void run() {
            //immutable integer class
            Integer a = 0;
            System.out.println(a); //output = 0
            foo(a);
            System.out.println(a); //output = 0
    
        }
    
        private void foo(Integer a) {
            a++; //new Integer object created behind the scenes
            System.out.println(a); //output = 1
        }
    }
    • dereferencing - if you want to dereference a at foo it is possible, but you will dereference only the foo's copy of a and not the a belonging to run:
    public class TestClass {
    
        public void run() {
          //mutable Integer class
          AtomicInteger a = new AtomicInteger(0);
          System.out.println(a); //output = 0
          foo(a); //this a still points at the same place in memory
          System.out.println(a); //output = 0
    
      }
    
      private void foo(AtomicInteger a) {
          AtomicInteger b = new AtomicInteger(1);
          a = b; //local reference a now points at b
          System.out.println(a); //output = 1
        }
    }

2. How to hack into String with reflection?

The way to mutate String in function through reflection is like below (the original example I have seen somewhere in the web but I cut some of the dead wood to leave the essence). Notice how string pool modification is changing "Immutable":

import java.lang.reflect.Field;

public class MutableString {

    public static void main(String[] args) {
        String s = "Immutable";
        String b = "Immutable";
        String c = new String(b.toCharArray(), 4, b.length() - 4);
        String t = "Notreally";

        mutate(s, t);
        System.out.println(t); //this will print Notreally
        System.out.println(b); //this will print Notreally!!!!
        System.out.println("Immutable"); //this will print Notreally!!!!
        System.out.println(c); //this will print table
    }

    // change the first min(|s|, |t|) characters of s to t
    public static void mutate(String s, String t) {
        try {
            Field val = String.class.getDeclaredField("value"); //characters storage ->  private final byte[] value;
            val.setAccessible(true);

            byte[] value = (byte[]) val.get(s);
            for (int i = 0; i < Math.min(s.length(), t.length()); i++) {
                value[i] = (byte) t.charAt(i); //here is the actual muatation of string "Immutable"
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3 Classes within classes

Java allows to defined classes within classes. As per official documentation available here, the hierarchy would be the following:

  • nested classes (i.e. class declared within other class)
    • static nested classes - declared with a keyword static
    • inner classes - declared without a keyword static

4. Static nested classes - instantiation

The static nested class must be instantiated prior to access to their non-static elements:

The static keyword makes it accessible without the need to create an instance of the surrounding class. But the class is not automatically instantiated (such feature would be really tough to achieve without imposing serious limitations on such type of classes). In principle one may memorize, that the static nested class is no different in its behavior to other top level classes. In particular, it does not have a reference to its surrounding class and it cannot access its private members (contrary to inner classes).

5. Diamond problem

Maybe that is obvious but I put it for the record - without overriding default def() method, TestClass cannot implement both interfaces A and B, as def() exists as default method at both interfaces. Still the access to 'def()' from both interfaces is not lost as seen in the example below:

public interface A {
    void foo();

    default void def(){
        System.out.println("Def from A");
    }
}

public interface B {
    void foo();

    default void def() {
        System.out.println("Def from B");
    }

}

class TestClass implements A, B {
    @Override
    public void foo() {
        System.out.println();

    }

    @Override
    public void def() {
        A.super.def(); //this calls default from A
        B.super.def(); //this calls default from B
    }
}

6. Closures in Java

6.1 Final and effectively final

Below example with wrapper is strange - seems I am effectively passing a non-final variable to to the stream which is prohibited. Need to think this through:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static java.util.stream.Collectors.toList;

public class EffectivelyFinal {

    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>(Arrays.asList(0,1,2,3,4,5,6,7,8,9));

        Integer nonFinal = 1;
        List<Integer> wrapper = new ArrayList<>();
        wrapper.add(nonFinal);
        nonFinal++;
        wrapper.set(0,nonFinal);

        //below works and returns 0,2,4,6,8
        System.out.println(
                numbers.stream()
                        .filter(a -> a % wrapper.get(0).intValue()==0) 
                        .collect(toList())
        );

       Integer effectivelyFinal = 3;
       // c++;
        //below works and returns 0,3,6,9 ; it will not compile if above line is uncommented
        System.out.println(
                numbers.stream()
                        .filter(a -> a % effectivelyFinal ==0) 
                        .collect(toList())
        );
    }
}

6.2 The common example with twice and triple - lambda and anonymous class

Below is another closure example. twice and triple are accompanied by their lexical scopes.

public class Multiplier {

    public Integer factor;

    public Function<Integer, Integer> getMultiplier(Integer factor) {
        this.factor = factor;
        return ( x -> x*this.factor);
    }
}

public class main {

    public static void main(String[] args) {
        Function<Integer, Integer> twice = new Multiplier().getMultiplier(2);
        Function<Integer, Integer> triple = new Multiplier().getMultiplier(3);
        System.out.println(twice.apply(10)); //20
        System.out.println(triple.apply(10)); //30
        System.out.println(twice.andThen(triple).apply(10));//60 <- ugly? lovely?
    }
}

6.3 Yet another example of closure - shortest from those short - two lambdas

This is yet another implementation of multiplier - this time with two lambdas.

import java.util.function.Function;

public class ShortClosure {

    public static void main(String[] args) {
        Function<Integer, Function<Integer, Integer>> multiplierProvider = multiplier -> number -> multiplier * number;
        Function<Integer, Integer> multiplyBy2 = multiplierProvider.apply(2);
        System.out.println(multiplyBy2.apply(2)); //4
    }
}