views:

406

answers:

5

Hi there

I'm a .NET guy originally, working in Java recently, and finding I'm really missing LINQ to Objects, specifically for performing filtering against collections.

A few people here on Stack Overflow have answered the "LINQ for Java?" question with a single word :

Quaere

However, on the site it clearly states "Pre-Beta", and there's been no commits to their code for over a year, so I'm guessing the project is pretty much dead.

Is anyone actually using this, and / or have any experience with it?

The second most common answer appears to be "use Google Collections". Is this the most appropriate Java way?

Cheers

Marty

+1  A: 

For simple Linq To Objects, the best I think can be done in Java is something like this:

Vector<Integer> numbers = new Vector<Integer>();

numbers.add(42);
numbers.add(3);
numbers.add(16);
numbers.add(92);
numbers.add(9);

Iterable<Integer> filtered = new Where<Integer>(numbers) {
    protected boolean predicate(Integer i) { return i > 10; }
};

Iterable<String> converted = new Select<Integer, String>(filtered) {
    protected String select(Integer i) { return i.toString(); }
};

for (final String str : converted)
    System.out.println(str);

Note that I haven't got Where and Select chaining together in one expression. I could insert the definition of filtered into the one place it's used, but that would probably make it (even) less readable. The problems are the lack of extension methods and lambdas. The closest we can get to lambdas is by these anonymous class declarations. They can refer to objects named in the enclosing scope, but only finals, so they cannot mutate anything (unlike lambdas in C#).

Also the hugely verbose syntax is a pain. People have often proposed that Java should offer a simpler syntax for cases where there is only one abstract (or interface) method, and hence there is no need to give the name or type declarations for what you want to override. Then there's the fact that there's no type inference, and no obvious way to provide it on generic class constructors because new Select(filtered) already means something else.

The implementations for Select and Where are:

abstract class Select<TSource, TResult> implements Iterable<TResult>
{
    private Iterable<TSource> _source;

    public Select(Iterable<TSource> source)
        { _source = source; }

    private class Iter implements Iterator<TResult>
    {
        private Iterator<TSource> _i;

        public Iter() { _i = _source.iterator(); }

        public void remove()
            { _i.remove(); }

        public boolean hasNext()
            { return _i.hasNext(); }

        public TResult next()
            { return select(_i.next()); }
    }

    protected abstract TResult select(TSource source);

    public Iterator<TResult> iterator()
        { return new Iter(); }
}

abstract class Where<TSource> implements Iterable<TSource>
{
    private Iterable<TSource> _source;

    public Where(Iterable<TSource> source)
        { _source = source; }

    private class Iter implements Iterator<TSource>
    {
        private Iterator<TSource> _i;
        private TSource _cachedNext;
        private boolean _hasCachedNext;

        public Iter()
        {
            _i = _source.iterator();
            fetch();
        }

        public void remove()
            { _i.remove(); }

        public boolean hasNext()
            { return _hasCachedNext; }

        public TSource next()
        {
            TSource result = _cachedNext;
            fetch();
            return result;
        }

        private void fetch()
        {
            _hasCachedNext = false;

            while (_i.hasNext())
            {
                _cachedNext = _i.next();
                if (predicate(_cachedNext))
                {
                    _hasCachedNext = true;
                    return;
                }
            }
        }
    }

    protected abstract boolean predicate(TSource source);

    public Iterator<TSource> iterator()
        { return new Iter(); }
}
Daniel Earwicker
A: 

There is the extra166y addendum to JSR166y with the ParallelArray construct. Basically a PLINQ for object arrays.

kd304
+3  A: 

You can select the items in a collection (and much more) in a more readable way by using the lambdaj library

http://code.google.com/p/lambdaj/

Mario Fusco
+1 Looks very nice, thanks for the link.
skaffman
Yep, been using lambaj for a while since posting the question (but forgot to update.)Thanks for the link -- it really is a great project.
Marty Pitt
I personally don't understand the hype around LINQ at all, especially after seeing what LambdaJ does (and how!). Definately worth a +1.
Esko
A: 

Quaere is in a pioneer position with LINQ in Java, but is not typesafe, which is one of the main points of LINQ.

Querydsl is type-safe and supports filtering, sorting and projecting Collections : http://source.mysema.com/display/querydsl/Querydsl

It supports operations on JPA/Hibernate, JDO and SQL backends as well.

The syntax is similar to SQL with the difference that the basic order is from-where-list.

I am the maintainer of Querydsl, so this answer is biased.

Timo Westkämper
A: 

SBQL4J may satisfy Your requirements. It's type safe extension to Java language, but it's also 100% compatible with Java 6 VM. SBQL4J provides capabilities similar to LINQ-to-objects.

Daniel's query examples should be like this:

Vector<Integer> numbers = new Vector<Integer>();

numbers.add(42);
numbers.add(3);
numbers.add(16);
numbers.add(92);
numbers.add(9);

Iterable<Integer> filtered = #{ numbers as n where n > 10 };

Iterable<String> converted = #{ numbers.toString() };

for (final String str : converted)
    System.out.println(str);

There are about 35 operators of the query language, including selection, projection, ordering, arithmetic operators, aggregation, transitive closure, range, etc.

Emil Wcisło