簡體   English   中英

StringBuilder 到 Streams 和 Lambda 表達式

[英]StringBuilder to Streams and Lambda expressions

我有一個方法:

public String tpeResponse(InputStream is) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder out = new StringBuilder();
        String line;

        while ((line = reader.readLine()) != null) {
            out.append(line);
        }
        reader.close();
        is.close();
        return out.toString();
}

在線: out.append(line); 我有一個錯誤:

java.lang.OutOfMemoryError:Java 堆空間

請幫助我使用 Streams 和 lambda 表達式重建這個方法。

無論你正在閱讀從數據(這is傳遞到方法變量)或者是

  • [A] 無窮無盡(例如,如果它是System.in ,它是一個InputStream代表您的流程標准輸入,並且您使用java -jar yourapp.jar </dev/null啟動應用程序,那么它實際上是無窮無盡的。

  • 或者,[B]不是無端的,但數據的LOT。 例如,相同的情況,但您執行java -jar yourapp.jar </my/20gigabyte4kCopyOfTheEntireLordOfTheRingsTrilogy.mp4

StringBuilder只是將所有數據存儲在有限的進程內存中。 限制到什么程度? 好吧,當然不會超過您計算機中的 RAM 總量,但通常會少於此數量,這取決於您如何啟動 JVM。 但是,如果您達到了該限制,那么答案是無論如何都不要使用 StringBuilder。

有幾種解決方案。 哪一個是正確的? 從您在問題中提供的有限細節無法判斷:

  • 意識到它是無限輸入,因此根本不可能嘗試存儲所有輸入。
  • 采用流模型,而不是將所有輸入轉換為一個大字符串然后處理該字符串,而是獲取足夠的輸入,您可以對其進行操作,對其進行操作,然后繼續進行。

例如,假設您有一個應用程序,它計算輸入流中“嘿”一詞出現的次數。

而不是像你那樣寫,而是你可以這樣做:

public int countHey(InputStream is) {
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    String line;

    int total = 0;
    while ((line = reader.readLine()) != null) {
        total += countHeyInLine(line);
    }
    reader.close();
    is.close(); // WARNING! SEE BELOW!
    return total;
}

即使您向它提供莎士比亞收集的作品,這段代碼也能工作,因為這段代碼讀取一行,處理該行,將此處理的結果減少為單個值,然后繼續:Java 的垃圾收集器可以簡單地收集所有行已經處理了,因此這段代碼將愉快地挖掘你扔給它的所有數百萬行,而不會耗盡內存。

NB:無論打開一個資源還是應該關閉它,或者需要非常清楚地標記它會將關閉它的責任轉移給調用它的人。 您做了相反的操作:此方法不是創建該輸入流的代碼,而是您正在關閉它。 這是一個非常糟糕的主意,會導致資源泄漏。 您不應該關閉is並在文檔中明確表示您的代碼沒有。 或者,如果您認為最好關閉此方法is ,則它應該在 try/finally 結構中關閉,以便調用者可以放心,調用此方法將最終以一種或另一種方式關閉該流。

使用 try-with-resources 是處理關閉資源的更好方法,當 BufferedReader 關閉時,底層 InputStream 將被關閉

    public String tpeResponse(InputStream is) {
        StringBuilder out = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
        String line;
        while ((line = reader.readLine()) != null) {
            out.append(line);
        }
        //reader.close(); // no need to close it explicitly
        // is.close(); // not needed
        
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return out.toString();

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM