2015-05-13 13 views
15
FileWriter writer = new FileWriter(output_file); 
    int i = 0; 

    try (Stream<String> lines = Files.lines(Paths.get(input_file))) { 
     lines.forEach(line -> { 
      try { 
       writer.write(i + " # " + line + System.lineSeparator()); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
        ); 
     writer.close(); 
    } 

Potrzebuję napisać wiersz z numerem linii, więc próbowałem dodać licznik do .forEach(), ale nie mogę go uruchomić. Po prostu nie wiem, gdzie umieścić i ++; do kodu, losowe skręcanie nie pomogło do tej pory.Jak wstawić licznik do strumienia <String> .forEach()?

+0

Deklaracja int poza pętlą, ustaw ją na 0 i zwiększ ją w każdej iteracji. – Stultuske

+0

@Stultuske Czy to działa? Próbowałeś tego? Zauważ, że tutaj nie ma żadnej pętli, ale istnieje lambda. – immibis

+0

To jest pytanie, mam int i = 0; poza lambdą, ale nie mogę go zwiększyć w każdym cyklu. Każdy(). Stultuske ani nie czytał kodu, ani pytania, tylko temat. – Vega

Odpowiedz

9

Jest to dobry przykład miejsca, w którym powinieneś raczej użyć dobrej staroświeckiej pętli for. Podczas gdy Files.lines() konkretnie podaje sekwencyjny strumień, strumienie mogą być wytwarzane i przetwarzane w kolejności, więc wstawianie liczników i poleganie na ich zamówieniu jest raczej złym nawykiem. Jeśli nadal chcesz to zrobić, pamiętaj, że wszędzie, gdzie możesz użyć lambda, nadal możesz korzystać z pełnej anonimowej klasy. Anonimowe klasy są normalnymi klasami i mogą jako takie mieć stan.

Więc w swojej przykład można zrobić tak:

FileWriter writer = new FileWriter(output_file); 

try (Stream<String> lines = Files.lines(Paths.get(input_file))) { 
    lines.forEach(new Consumer<String>() { 
     int i = 0; 
     void accept(String line) { 
      try { 
       writer.write((i++) + " # " + line + System.lineSeparator()); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
    writer.close(); 
} 
37

Możesz użyć AtomicInteger jako zmiennego licznika final.

public void test() throws IOException { 
    // Make sure the writer closes. 
    try (FileWriter writer = new FileWriter("OutFile.txt")) { 
     // Use AtomicInteger as a mutable line count. 
     final AtomicInteger count = new AtomicInteger(); 
     // Make sure the stream closes. 
     try (Stream<String> lines = Files.lines(Paths.get("InFile.txt"))) { 
      lines.forEach(line -> { 
         try { 
          // Annotate with line number. 
          writer.write(count.incrementAndGet() + " # " + line + System.lineSeparator()); 
         } catch (Exception e) { 
          e.printStackTrace(); 
         } 
        } 
      ); 
     } 
    } 
} 
+0

@ AndreaTaroni86 - Dlaczego? – OldCurmudgeon

4

Jak stwierdzono w Java doc:

dowolnej zmiennej lokalnej, formalnego parametru lub parametr wyjątków używana ale nie zadeklarowane w lambda wyrażenie musi być albo deklarowane jako ostateczne, albo być efektywnie ostateczne (§4.12.4), albo wystąpił błąd podczas kompilacji, gdy próbowano użyć.

Oznacza to, że zmienna musi być ostateczna lub efektywna. Chcesz dodać licznik do forEach, a do tego możesz użyć wartości AtomicInteger zgodnie z sugestią OldCurumudgeon, która jest preferowana przez IMO.

Wierzę, że można również użyć tablicy mającej tylko jedną wartość 0, której można użyć jako licznika. Sprawdź i daj mi znać, jeśli poniższy przykład działa:

public void test() throws IOException { 
    FileWriter writer = new FileWriter("OutFile.txt"); 
    final int[] count = {0}; 

    try (Stream<String> lines = Files.lines(Paths.get("InFile.txt"))) { 
     lines.forEach(line -> { 
      try { 
       count[0]++; 
       writer.write(count[0] + " # " + line + System.lineSeparator()); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     ); 
     writer.close(); 
    } 
} 
Powiązane problemy