2

複数のサブリストからリストを作成するコードを書いていることがよくあります。簡単な例として、リストに対して検証する必要があるリストがあるとします。これを (命令的に) 書く 1 つの方法は次のようになります。

import static com.google.common.collect.Lists.newArrayList;

import java.util.List;

public class Product {

    private String name;
    private int height;

    public static List<String> validateList(List<Product> products) {
        List<String> result = newArrayList();
        valideListSize(products, result);
        for (Product product : products) {
            product.validate(result);
        }
        return result;
    }

    private static void valideListSize(List<Product> products,
            List<String> result) {
        if (products.size() > 1000) {
            result.add("List too large");
        }
    }

    private void validate(List<String> result) {
        if (name.length() > 30) {
            result.add("Name contains too many characters");
        }
        if (height > 40) {
            result.add("Product too high");
        }
    }

}

ただし、単純化/保守/再利用のために、単一の製品を検証するロジックを、検証結果のリストを別の既存のリストに追加することに結び付けたくありません。また、パラメーターを変更すると、コードのデバッグがより困難になる可能性があると思います。だから私はより機能的なスタイルを好みます。現在、私は通常、次のように記述します (Google Guava の newArrayList を使用):

import static com.google.common.collect.Lists.newArrayList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;

import java.util.List;

public class Product {

    private String name;
    private int height;

    public static List<String> validateList(List<Product> products) {
        List<String> result = newArrayList();
        result.addAll(valideListSize(products));
        for (Product product : products) {
            result.addAll(product.validate());
        }
        return result;
    }

    private static List<String> valideListSize(List<Product> products) {
        if (products.size() > 1000) {
            return singletonList("List too large");
        }
        return emptyList();
    }

    private List<String> validate() {
        List<String> result = newArrayList();
        if (name.length() > 30) {
            result.add("Name contains too many characters");
        }
        if (height > 40) {
            result.add("Product too high");
        }
        return result;
    }

}

これにより、有効期間が非常に短い多数の小さな配列リストが作成され、その多くは通常空になります (検証エラーはありません)。この種のコードは実際には非効率的でしょうか、それとも本番環境でこのスタイルを使用しても問題ありませんか? コードをクリーンで読みやすく、Java のベスト プラクティスに準拠させながら、必要なことを行うより効率的な方法 (おそらく Guava を使用) はありますか?

プロの Java 開発者として何をしますか?

編集:最初のコメントで私の回答を参照してください。なぜ私は2番目の方法を好むのですか? 私は時期尚早の最適化よりもコードの保守性/可読性を好みますが、日常のプログラミングでこの種のパターンをよく目にするため、少なくとも同じくらいクリーンな簡単な方法があるかどうか疑問に思っています。Iterables.concat などの結合リスト ビューを使用する場合はどうでしょうか。それとも、それも多くの中間クラスを作成しますか?

4

2 に答える 2

0

これは、union-find データ構造とも呼ばれるDisjoint-set データ構造を使用して効率的に達成できる場合があります。オンラインで利用できるいくつかの実装があります

于 2013-04-11T15:47:13.323 に答える
0

私自身の質問に答えるには: 単一製品の検証メソッド内で多くの新しいリストを作成する場合でも、Java は優れたパフォーマンスを発揮します。300000 個の製品のリストを 10 回 (ウォームアップ後) 検証する時間を計りました。

1 つの Arraylist が渡される最初の実装には 275 ミリ秒かかります。LinkedList を使用すると、300 ミリ秒かかります。中間の ArrayList が作成される可能性のある 2 番目の実装には、760 ミリ秒かかります。LinkedList の使用には 580 ミリ秒かかります。Guava の ImmutableList ビルダーを使用すると、1150 ミリ秒かかります。

したがって、私は単純に 2 番目の方法を使用し続けると思います (おそらく、ランダム アクセスを必要としない小さなリストには LinkedList を使用します)。

于 2013-04-19T09:34:49.020 に答える