Blog-Archiv

Mittwoch, 14. Oktober 2015

Iterator in Java and JS

Although I think that JavaScript is nearer to C than to Java, I would like to make a juxtaposition of the two languages in this Blog. It won't be so much about what the one can do and the other can't, it'll be more about how to implement a Java class using JavaScript.

Java Iterator

A nice small example would be the implementation of an array Iterator. This is a stateful object that always holds the index of the latest accessed array member.

A stateful object is one that does not look the same all the time, it changes during its lifetime.
For example a Java List could change, members may be added or removed, or the order could be changed. You could call it mutable.
On the other hand a Java Integer Object is stateless, it does not ever change, it always stays the number it is. New numbers could evolve from add- or subtract-operations with numbers. You could call this immmutable or final.

The Iterator tells you whether there is another member that has not yet been accessed, and it gives you that next member when so. As soon as you retrieve the next member, its internal index will skip to the next if present. Once the iterator has been consumed it is not usable any more, it must be instantiated (constructed) again for a new iteration.

The iterator abstracts the nature of the iterated collection, which could be a tree, a graph, a list, a table. You do not need to implement any loop counter when using Iterator. Iterator is a design pattern, very recommendable for achieving reusable code with high abstraction level.

So here is a simple Java implementation of iterator:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class Iterator
{
    private final Object [] list;
    private int index;
    
    public Iterator(Object [] list) {
        this.list = list;
    }

    public boolean hasNext() {
        return index < list.length;
    }

    public Object next() {
        int i = index;
        index++;
        return list[i];
    }
}

This should be easy to read. There is a class Iterator that has a constructor that requires an array to iterate (would make no sense without). It stores the given array into a private final member field (private: not visible outside the class, final: can not be modified any more from inside the class). The second private field is the index that will be used to iterate through the array. The class exposes two public methods to the outer world, one returns whether there is another member available, the other returns the next member.

A perfect capsule, binding together data and functions like the OO idea demands.

JavaScript Iterator

To achieve the same in JavaScript we have to know a lot about this language, especially about closures. Simply spoken a closure is a block of code that remembers its environment, but this is a little bit too general. In JavaScript, closures are instantiated function bodies. In Java until version 8, a closure could be realized for example by implementing a Runnable, whereby all environmental variables had to be final to be accessible by the Runnable body. In Java 8, closures have been named lambdas, and there is a special syntax for them.

But before going too much into details, here is the JavaScript iterator.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
var newIterator = function(list)
{
    var index = 0;
    var that = {};
    
    that.hasNext = function() {
        return index < list.length;
    };
    
    that.next = function() {
        var i = index;
        index++;
        return list[i];
    };
    
    return that;
};

The first line declares a function called "newIterator". I could also have called it "iteratorFactory", but I wanted to make clear that this function resembles a Java class constructor.

This function exists in the global context (use AMD when you want to avoid such). For a browser, the global context would be the window object.

The closure starts with the opening { brace of the function, and with the closing } brace it ends. All declared parameters of the function, and all its local var variables, will be visible and accessible from inside the function, and from any function or object declared inside this function, down to any depth. And even when there will be new objects generated from inside and returned to the outer world, these would all see the same parameter values and local variables, even when the function gets called several times with different parameter values. Parameter values would get copied, and local variables would get instantiated newly, on every function call.

So there is an invisible JS mechanism that binds parameters and variables of a certain function call to the code blocks existing inside. This invisible environment is called closure (or lambda) in JS. A function call generates a closure, and that closure copies the current values of parameters, and the closure will survive the function call when it is referenced by some function or object generated inside the function and returned to the outer world.
Mind that a normal { block of code } is NOT a closure in JS! Only functions can provide them.

Using the closure mechanism we can declare the index as local variable within the body of the newIterator function. It will be visible and accessible from the returned that object and its hasNext() and next() functions. The same applies to the list parameter. Any call of newIterator() will generate a new closure, binding together the list, the index and the that object.

Thus we can use factory-functions to imitate both Java classes and constructors at the same time in JS. We can then return an object that uses a closure which holds references to all parameters and variables of the factory function. This might look a little bit unusual for OO developers, but it works fine.


Here they are once more, side by side, for the eye to get used to it, left JavaScript, right Java.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
var newIterator = function(list)
{
    var index = 0;
    var that = {};
    
    that.hasNext = function() {
        return index < list.length;
    };
    
    that.next = function() {
        var i = index;
        index++;
        return list[i];
    };
    
    return that;
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class Iterator
{
    private final Object [] list;
    private int index;
    
    public Iterator(Object [] list) {
        this.list = list;
    }

    public boolean hasNext() {
        return index < list.length;
    }

    public Object next() {
        int i = index;
        index++;
        return list[i];
    }
}



Keine Kommentare: