5
public class Parser {

    public static void main(String[] args) {
        Parser p = new Parser();
        p.matchString();
    }

    parserObject courseObject = new parserObject();
    ArrayList<parserObject> courseObjects = new ArrayList<parserObject>();
    ArrayList<String> courseNames = new ArrayList<String>();
    String theWebPage = " ";

    {
        try {
            URL theUrl = new URL("http://ocw.mit.edu/courses/");
            BufferedReader reader =
                new BufferedReader(new InputStreamReader(theUrl.openStream()));
            String str = null;

            while((str = reader.readLine()) != null) {
                theWebPage = theWebPage + " " + str;
            }
            reader.close();

        } catch (MalformedURLException e) {
            // do nothing
        } catch (IOException e) {
            // do nothing
        }
    }

    public void matchString() {
        // this is my regex that I am using to compare strings on input page
        String matchRegex = "#\\w+(-\\w+)+";

        Pattern p = Pattern.compile(matchRegex);
        Matcher m = p.matcher(theWebPage);

        int i = 0;
        while (!m.hitEnd()) {
            try {
                System.out.println(m.group());
                courseNames.add(i, m.group());
                i++;
            } catch (IllegalStateException e) {
                // do nothing
            }
        }
    }
}

上記のコードで達成しようとしているのは、MIT OpencourseWare Web サイトで部門のリストを取得することです。ページソースのように、部署名のパターンに一致する正規表現を使用しています。そして、Pattern オブジェクトと Matcher オブジェクトを使用して、正規表現に一致するこれらの部門名を find() して出力しようとしています。しかし、コードの実行には永遠に時間がかかります.bufferedReaderを使用してWebページを読み取るのにそれほど時間がかかるとは思いません. だから、私はひどく間違ったことをしているのか、ウェブサイトの解析に途方もなく長い時間がかかっていると思います. そのため、パフォーマンスを改善する方法やコードの間違いを修正する方法について、ご意見をいただければ幸いです。コードの書き方が悪くてすみません。

4

3 に答える 3

13

問題はコードにあります

while ((str = reader.readLine()) != null)
    theWebPage = theWebPage + " " +str;

変数theWebPageは文字列であり、不変です。読み取られた行ごとに、このコードは、これまでに読み取られたすべてのコピーにスペースと読み取られたばかりの行が追加された新しいString を作成します。これは異常な量の不必要なコピーであり、プログラムの実行速度が非常に遅いのはそのためです。

問題の Web ページをダウンロードしました。55,000 行あり、サイズは約 3.25MB です。大きすぎない。しかし、ループ内のコピーにより、最初の行は約15 億回 (55,000 の 2 乗の 1/2) コピーされることになります。プログラムは、コピーとガベージ コレクションにすべての時間を費やしています。これをラップトップ (2.66GHz Core2Duo、1GB ヒープ) で実行したところ、ローカル ファイルからの読み取りで実行に 15 分かかりました (ネットワーク遅延や Web クローリング対策なし)。

これを修正するtheWebPageには、代わりに aを作成しStringBuilder、ループ内の行を次のように変更します。

    theWebPage.append(" ").append(str);

必要に応じて、ループの後にtheWebPage使用して文字列に変換できます。toString()修正版を実行したところ、ほんの一瞬でした。

{ }ところで、コードはクラス内で裸のコード ブロックを使用しています。これはインスタンス初期化子です(静的初期化子ではありません)。オブジェクトの構築時に実行されます。これは合法ですが、非常に珍しいことです。他のコメント投稿者を誤解させたことに注意してください。このコード ブロックを名前付きメソッドに変換することをお勧めします。

于 2012-08-11T03:54:26.000 に答える
2

これはあなたのプログラム全体ですか?の宣言はどこにありparserObjectますか?

main()また、このコードはすべて、呼び出す前にあなたの中にあるべきではありませんmatchString()か?

parserObject courseObject = new parserObject();
ArrayList<parserObject>  courseObjects = new ArrayList<parserObject>();
ArrayList<String> courseNames = new ArrayList<String>();
String theWebPage=" ";
{

    try {
            URL theUrl = new URL("http://ocw.mit.edu/courses/");
            BufferedReader reader = new BufferedReader(new InputStreamReader(theUrl.openStream()));
            String str = null;

            while((str = reader.readLine())!=null)
            {
                theWebPage = theWebPage+" "+str;
            }
            reader.close();

    } catch (MalformedURLException e) {

    } catch (IOException e) {

    }
}

また、例外をキャッチしていて、エラー メッセージを表示していません。例外が発生した場合は、常にエラー メッセージを表示し、何かを行う必要があります。たとえば、ページをダウンロードできない場合、空の文字列を解析しようとする理由はありません。

あなたのコメントから、クラスの静的ブロックについて学びました(ありがとう、それらについて知りませんでした)。ただし、私が読んだことからstatic、ブロックの開始前にキーワードを配置する必要があります{mainまた、 MalformedURLException または IOException が発生した場合に終了できるように、コードを に配置した方がよい場合もあります。

于 2012-08-11T02:05:54.313 に答える
1

もちろん、限定された JDK 1.0 API を使用してこの課題を解決し、Stuart Marks が優れた回答で解決を支援した問題に遭遇することもできます。

または、たとえばApache Commons IOなどの一般的な事実上の標準ライブラリを使用し、次のような簡単な方法で Web サイトを String に読み込みます。

// using this...
import org.apache.commons.io.IOUtils;

// run this...
try (InputStream is = new URL("http://ocw.mit.edu/courses/").openStream()) {
    theWebPage = IOUtils.toString(is);
}
于 2015-02-18T10:04:24.793 に答える