Framework as seen from Java, Part 1


Published: 2016-11-20
Updated: 2016-11-20
Web: https://fritzthecat-blog.blogspot.com/2016/11/framework-as-seen-from-java-part-1.html


The term "Framework" is somehow overburdened with individual and company-specific meanings. When you hear this word, it could designate ....

Little bit of truth in all of them?
Wikipedia states that it is ....

A Framework must be something big and complex. That's the impression you get from literature. I believe that "Framework" expresses the undefined hopes and visions of software thinkers, similar to "Component". There is no precise and generally accepted definition of this term. I stick to the old Catalysis way to understand it. But they talk on UML level, and I want to give the view of a Java developer. For me, framework means Reusability by Abstraction.

The Smallest Framework Ever

"Swapping" abstracts the interchange of two elements in an ordered container. Widely used in books about software to explain generic types. Swapping is needed for example in sort-algorithms. Its responsibility:

  1. In a container (array, list, ...) you have two elements at certain indexes, and you want to exchange them, so that element 1 is where element 2 was before, and vice versa.
  2. It is not possible to return a new container, swapping must be done directly in the given container
        final Integer[] array = ....;
final int index1 = ....;
final int index2 = ....;

final Integer element1 = array[index1];
array[index1] = array[index2];
array[index2] = element1;

The problem is that you want to implement the swapping of two elements generically once-and-only-once, and you want it strongly typed. But there is a small problem in the few lines of code to do that.

So you either need to hard-code swapping for every thinkable element-type that may need such, or you have a language mechanism that allows generic types. Generic types were introduced in Java 1.5. They make it possible to use an arbitrary (generic) type T instead of a specific type Integer. In older Java-versions you could have done this using the "generic" Java super-class java.lang.Object, but this would not have been type-safe. When using Java generics, the compiler checks the type of the elements that should be in the container, and all related code working on them.

In the following, I use Java generics to implement a type-safe and though generic swap.

public class Swap<T>
{
public void swap(T [] array, int index1, int index2) {
final T element1 = array[index1];
array[index1] = array[index2];
array[index2] = element1;
}
}

Here is some test-code to try this out.

public class Demo
{
public static void main(String[] args) {
final Integer[] integerArray = new Integer[] { 0, 1, };
System.out.println("Before array swap: "+Arrays.asList(integerArray));

new Swap<Integer>().swap(integerArray, 0, 1);

System.out.println("After array swap: "+Arrays.asList(integerArray));
}
}

Output is:


Before array swap: [0, 1]
After array swap: [1, 0]

Extensions

You might ask now "Where is reusability and abstraction?". Abstraction was done by the Java generics. In case of reusability, you're right. I can not reuse these three lines of code for e.g. List. Nevertheless I can write another Swap that cares about java.util.List. It makes no sense to extend Swap, because there is nothing reusable in it.

List

import java.util.List;

public class SwapInList<T>
{
public void swap(List<T> list, int index1, int index2) {
final T element1 = list.get(index1);
list.set(index1, list.get(index2));
list.set(index2, element1);
}
}

Test-code:

        final List<String> stringList = new ArrayList<>();
stringList.add("A");
stringList.add("B");
stringList.add("C");
stringList.add("D");
stringList.add("E");
System.out.println("Before list swap: "+stringList);

new SwapInList<String>().swap(stringList, 1, 3);

System.out.println("After list swap: "+stringList);

Outputs:


Before list swap: [A, B, C, D, E]
After list swap: [A, D, C, B, E]

Unfortunately there is no Java interface that makes array and list interchangeable. I must access the array by indexing, and the list by calling get() and set().

Linked Set

There is another ordered Java container that may need swapping. Other than List, a Set contains no duplicates, and has no order. LinkedHashSet is different, it keeps the order in which elements were added.

Working with Set means you have no get() and set(). Again we need another implementation for swapping elements.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.util.LinkedHashSet;
import java.util.Set;

public class SwapInLinkedSet<T>
{
public void swap(Set<T> linkedSet, int index1, int index2) {
if (index1 == index2) // fast and easy: nothing to do
return;

// uncover mistakes early
if (index1 < 0 || index2 < 0 || index1 >= linkedSet.size() || index2 >= linkedSet.size())
throw new IllegalArgumentException("Swap-indexes out of bounds!");

// retrieve elements at given indexes
int i = 0;
T element1 = null;
T element2 = null;
for (final T element : linkedSet) {
if (i == index1)
element1 = element;
else if (i == index2)
element2 = element;

i++;
}

// create a clone and clear the original set
final LinkedHashSet<T> clone = new LinkedHashSet<>(linkedSet);
linkedSet.clear();

// establish new order in original set
i = 0;
for (final T element : clone) {
if (i == index1)
linkedSet.add(element2);
else if (i == index2)
linkedSet.add(element1);
else
linkedSet.add(element);

i++;
}
}
}

Oops, these are definitely more than three lines. Unfortunately the nature of Java Set makes it impossible to access specific indexes. That is the reason why we need two loops: first loop retrieves the elements to be swapped, second loop (over a clone) establishes the new order after having cleared the set completely.

        final Set<Float> floatList = new LinkedHashSet<>();
floatList.add(1.0f);
floatList.add(100.0f);
floatList.add(10000.0f);
System.out.println("Before linkedSet swap: "+floatList);

new SwapInLinkedSet<Float>().swap(floatList, 1, 2);

System.out.println("After linkedSet swap: "+floatList);

This test code outputs:


Before linkedSet swap: [1.0, 100.0, 10000.0]
After linkedSet swap: [1.0, 10000.0, 100.0]

Summary

These swaps maybe were examples for the abstraction that Java generics provide, but not for implementation abstraction, and definitely not for reusability. We had to use three different implementations for three different Java container types. Can we do better? You guessed right, I will try this in my next Blog article about frameworks as seen by Java.





ɔ⃝ Fritz Ritzberger, 2016-11-20