単純な Linq To Objects の場合、Java で実行できる最善の方法は次のようなものです。
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);
1 つの式で連結しWhere
ていないことに注意してください。Select
の定義をfiltered
それが使用されている 1 つの場所に挿入することもできますが、それではおそらく (さらに) 読みにくくなります。問題は、拡張メソッドとラムダがないことです。ラムダに最も近いのは、これらの匿名クラス宣言によるものです。それらは、囲んでいるスコープで名前が付けられたオブジェクトを参照できますが、final
s のみであるため、何も変更できません (C# のラムダとは異なります)。
また、非常に冗長な構文も苦痛です。抽象 (またはインターフェース) メソッドが 1 つしかない場合、Java はより単純な構文を提供するべきであると、人々はよく提案してきました。そのため、オーバーライドしたいものの名前や型宣言を指定する必要はありません。次に、型推論がなく、ジェネリック クラス コンストラクターでそれを提供する明白な方法がないという事実がありnew Select(filtered)
ます。
Select
との実装は次のWhere
とおりです。
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(); }
}