3

Javaでは、(文字の代わりに)オブジェクトをプルReaderすることで機能するの抽象バージョンはです。Iterator

問題は、オブジェクト(つまりインターフェイス)の抽象的なバージョンAppendableまたはWriterどこにプッシュできるかということです。

以前は、次のような独自のインターフェイスを作成していました。

public interface Pusher<T> {
    public void push(T o);
}

誰かが知っているほとんどの環境で利用できる汎用インターフェースはありますか?それは理にかなっているので、上記のインターフェースを作成し続ける必要はありませんか?

アップデート:

これが役立つ場所の例です。

public void findBadCategories(final Appendable a)  {
    String q = sql.getSql("product-category-bad");
    jdbcTemplate.query(q, new RowCallbackHandler() {
        @Override
        public void processRow(ResultSet rs) throws SQLException {
            String id = rs.getString("product_category_id");
            String name = rs.getString("category_name");
            if (! categoryMap.containsKey(id)) {
                try {
                    a.append(id + "\t" + name + "\n");
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    });
}

ここを使用してAppendableいますが、Pusherコールバックが必要です。Java 8がリリースされたら、クロージャを使用するだけですが、そのクロージャにはまだインターフェイスが必要です。

最後に、私が以前に選択した他のオプションは、GuavaPredicateまたはFunction(さらに悪いように見えますが)に完全に違反することです。これらはべき等であることを目的としているため、契約違反です(ただし、true常に戻ってきた場合は...)。

ただし、Guavaが提供するのは、 AbstractIteratorのおかげでPythonのジェネレーターに類似したものです。

私はGuavaに拡張機能の問題を追加しましたが、そのような基本的なものを追加するのは実際には彼らの仕事ではないことに同意します。

4

4 に答える 4

3

現在、いくつかのプロジェクトで、この目的のためにシンクと呼ぶものを定義しました。

interface Sink<T> {
  void put(T contribution);
}

これにより、型のオブジェクトを生成するメソッドは、型Tのパラメーターを要求しますSink<? super T>

いくつかの設計上の質問が発生します。

  • 宣言されているように、Sink#put()チェックされた例外はスローされません。これは、通常スローするI/O操作ではうまく機能しませんIOException。これに対処するために、この型Exceptionをスローする拡張およびアドバタイズする型パラメーターを追加できますput()が、その時点で、値の消費の性質についてよく知っている場合は、そのカスタムインターフェイスを定義する方がよいでしょう。

  • 宣言されSink#put()ているように、値を返しません。値が受け入れられたかどうかを発信者に示すことはできません。

  • このようなジェネリックインターフェイスでは、intやのようなプリミティブ型のコントリビューションをボックス化charする必要があります。これは、それらがnullになる可能性があることも意味します。contributionパラメータに。で注釈を付けることを検討してください@NonNull

PetrPudlákが彼の回答で言及しているジェネレーターの概念に関連して、このタイプに沿って、ソースインターフェイスを定義しました。

interface Source<T> {
  T get();
}

Tそのようなソースからタイプのアイテムを描画しようとするメソッドは、タイプのパラメーターを必要としますSource<? extends T>

並行プロセス間のチャネルとの調整のために、両方を定義しSink#put()、以下Source#get()をスローしInterruptedExceptionます。

interface Sink<T> {
  void put(T contribution) throws InterruptedException;
}


interface Source<T> {
  T get() throws InterruptedException;
}

これらは、時間指定の待機とメソッドに相当するものが欠けているものの、パッケージに組み込まれなかったDougLeaの元の Puttableインターフェイスに類似しています。Takablejava.util.concurrentPuttable#offer()Takable#poll()

次に、交換器、フィルター、変圧器など、簡単に構成できるあらゆる種類の実装が発生します。

私自身のライブラリを超えて、Guavaライブラリがハッシュ関連の目的のPrimitiveSinkためにとFunnelタイプを提供するのを見てきました。それらも有用な抽象化であることがわかるかもしれません。

于 2012-08-30T17:06:30.667 に答える
1

この主題については、いくつかの見解があります。

  1. イテレータのデュアルはジェネレータです。イテレータはコレクションから値を「消費」し、ジェネレータはそれらを「提供」します。しかし、ジェネレーターはライターとは少し異なります。ライターの場合、要素をいつプッシュするかを決定します。一方、ジェネレーターは、値のシーケンスを1つずつ提供します。Javaには、ジェネレーターに対する特定の言語サポートはありません。イテレータとジェネレータの違いは何ですか?も参照してください。

  2. イテレータの反対は、値をプッシュできるものです。Javaにはそのための抽象化はないと思います。私が見たクローズはScala'sGrowableclear()メソッドを無視)です。

于 2012-08-30T14:24:47.493 に答える
0

これが私がやろうと決心したことです(そして私は他の人が与えたものの中でそれが最良の選択肢だと思います:P)。

Java 8のLambdaクラスをバックポートします(java.util.functions.*)。特にこれ:

/**
 * Performs operations upon an input object which may modify that object and/or
 * external state (other objects).
 *
 * <p>All block implementations are expected to:
 * <ul>
 * <li>When used for aggregate operations upon many elements blocks
 * should not assume that the {@code apply} operation will be called upon
 * elements in any specific order.</li>
 * </ul>
 *
 * @param <T> The type of input objects to {@code apply}.
 */
public interface Block<T> {
/**
 * Performs operations upon the provided object which may modify that object
 * and/or external state.
 *
 * @param t an input object
 */
void apply(T t);

// Some extension methods that I'll have to do with below.
}

基本的に、のような新しい名前空間をcom.snaphop.backport.java.util.functions.*作成し、インターフェイス上を移動して、Guavaで機能するようにします。明らかに、ラムダ構文や拡張メソッドはありませんが、回避できるものがあります。理論的には、Java 8が登場したとき、私がしなければならないのは名前空間の切り替えだけです。

于 2012-08-31T19:58:36.273 に答える
0

最も近いのはObservableですが、あまり使用されていません。

public update(Observable o, Object arg)

Readerの代わりにIterableを使用せず、選択したコンシューマーを作成します。

一般的なパターンは、インターフェイスではなく注釈を使用することです。

例えば

@Subscriber
public void onUpdate(Update update) { }

@Subscriber
public void onInsert(Insert insert) { }

@Subscriber
public void onDelete(Delete delete) { }

このクラスがリスナーとして追加されると、サブスクライブし、Updateオブジェクトになり、他のクラスは無視されます。これにより、1つのオブジェクトがタイプセーフな方法で異なるタイプのメッセージをサブスクライブできます。InsertDelete

于 2012-08-30T14:04:05.080 に答える