Question

I would like some kind of generic method to allow me to lazy load a collections contents based on use of the java.util.Collection.get( int ) method. I found the Supplier interface in Guava and this looks like a great way of doing the lazy loading, but how to make the loading invisible in java collections is something I am struggling with.

Below is a sample lazy loading method that iterates through an iterator.

class MySupplier<T> implements Supplier<T> {
    private T s;
    public MySupplier( T s ) {
        this.s = s;
    }
    public T get() {
        System.out.println( String.format( "Lazy loading '%s'", s ) );
        return s;
    }
}

public void lazyLoad() {
    List<MySupplier<String>> list = Lists.newArrayList( new MySupplier<String>( "a" ), new MySupplier<String>( "a" ), new MySupplier<String>( "b" ), new MySupplier<String>( "c" ), new MySupplier<String>( "d" ) );
    for ( Iterator<MySupplier<String>> i = list.iterator(); i.hasNext(); ) {
        System.out.println( i.next().get() );
    }
}

I want to avoid having to use the Supplier.get() method if I can help it, but instead have a collections wrapper take care of it for me when Collection.get( int ) is called. I hope to achieve this in a simple method call that I called makeLazy( Collection ) below.

public void lazyLoad_desired() {
    List<String> list = makeLazy( 
            Lists.newArrayList( new MySupplier<String>( "a" ), new MySupplier<String>( "a" ), new MySupplier<String>( "b" ), new MySupplier<String>( "c" ), new MySupplier<String>( "d" ) )
        );
    for ( Iterator<String> i = list.iterator(); i.hasNext(); ) {
        String s = i.next();
        System.out.println( s );
    }
}

I realise that I would need to override collections somehow, but my knowledge in this area has some gaps. Could somebody give me some hints and tips on what I need to do to implement the makeLazy( Collection ) method?

Thanks, Stuart

Was it helpful?

Solution

Based on the discussion with Louis Wasserman I decided to take his advice and use an iterator. The solution below appears to be working for me.

class MySupplier<T> implements Supplier<T> {
    private T s;
    public MySupplier( T s ) {
        this.s = s;
    }
    public T get() {
        System.out.println( String.format( "Lazy loading '%s'", s ) );
        return s;
    }
}

public void lazyLoad() {
    List<MySupplier<String>> list = Lists.newArrayList( new MySupplier<String>( "a" ), new MySupplier<String>( "a" ), new MySupplier<String>( "b" ), new MySupplier<String>( "c" ), new MySupplier<String>( "d" ) );

    for ( Iterator<String> i = supplierIterator( list ); i.hasNext(); ) {
        System.out.println( i.next() );
    }
}

public static <T> Iterator<T> supplierIterator( Collection<? extends Supplier<T>> c ) {
    Function<Supplier<T>, T> function = Suppliers.supplierFunction();
    Iterable<T> iterable = Iterables.transform( c, function );
    return iterable.iterator();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top