2015-05-27 26 views
8

Próbuję nauczyć się korzystać z funkcji Java 8 (takich jak lambdy i strumienie) w moim codziennym programowaniu, ponieważ pozwala to na znacznie czystszy kod.Strumienie Java 8, lambdas

Oto, nad czym aktualnie pracuję: Otrzymuję strumień ciągów z lokalnego pliku z pewnymi danymi, które później przekształcam w obiekty. Struktura pliku wejściowego wygląda mniej więcej tak:

Airport name; Country; Continent; some number; 

A mój kod wygląda następująco:

public class AirportConsumer implements AirportAPI { 

List<Airport> airports = new ArrayList<Airport>(); 

@Override 
public Stream<Airport> getAirports() { 
    Stream<String> stream = null; 
    try { 
     stream = Files.lines(Paths.get("resources/planes.txt")); 
     stream.forEach(line -> createAirport(line)); 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    return airports.stream(); 
} 

public void createAirport(String line) { 
    String airport, country, continent; 
    int length; 


    airport = line.substring(0, line.indexOf(';')).trim(); 
    line = line.replace(airport + ";", ""); 
    country = line.substring(0,line.indexOf(';')).trim(); 
    line = line.replace(country + ";", ""); 
    continent = line.substring(0,line.indexOf(';')).trim(); 
    line = line.replace(continent + ";", ""); 
    length = Integer.parseInt(line.substring(0,line.indexOf(';')).trim()); 
    airports.add(new Airport(airport, country, continent, length)); 
    } 
} 

I w moim głównym klasy I iteracyjne nad strumieniem obiektu i wydrukować wyniki:

public class Main { 



public void toString(Airport t){ 
    System.out.println(t.getName() + " " + t.getContinent()); 
} 

public static void main(String[] args) throws IOException { 
    Main m = new Main(); 
    m.whatever(); 

} 

private void whatever() throws IOException { 
    AirportAPI k = new AirportConsumer(); 
    Stream<Airport> s; 
    s = k.getAirports(); 
    s.forEach(this::toString); 

} 


} 

Moje pytanie brzmi następująco: Jak mogę zoptymalizować ten kod, więc nie muszę analizować linii z pliku osobno, ale zamiast tego utworzyć strumień obiektów Lotnisko prosto z pliku źródłowego? Czy jest to zakres, w którym mogę to zrobić?

+3

Uwaga: powinieneś zamknąć plik: 'try (Stream lines = Files.lines (...)) {lines.map (xxx) .collect (...)};' – assylias

Odpowiedz

11

Musisz użyć map(), aby przekształcić dane w miarę ich przechodzenia.

Files.lines(Paths.get("resources/planes.txt")) 
    .map(line -> createAirport(line)); 

ta zwróci Stream<Airport> - jeżeli chcesz zwróci List, następnie będziesz musiał użyć metody collect na końcu.

Podejście to jest również bezpaństwowe, co oznacza, że ​​nie będzie potrzebna wartość na poziomie instancji na poziomie airports.

Musisz zaktualizować swoją metodę createAirport powrócić coś:

public Airport createAirport(String line) { 

    String airport = line.substring(0, line.indexOf(';')).trim(); 
    line = line.replace(airport + ";", ""); 
    String country = line.substring(0,line.indexOf(';')).trim(); 
    line = line.replace(country + ";", ""); 
    String continent = line.substring(0,line.indexOf(';')).trim(); 
    line = line.replace(continent + ";", ""); 
    int length = Integer.parseInt(line.substring(0,line.indexOf(';')).trim()); 
    return new Airport(airport, country, continent, length); 
} 

Jeśli szukasz bardziej funkcjonalnego podejścia do kodu, może warto rozważyć przepisanie createAirport tak nie robi zmodyfikuj linię. Konstruktorzy są również mili dla tego typu rzeczy.

public Airport createAirport(final String line) { 
    final String[] fields = line.split(";"); 
    return new Airport(fields[0].trim(), 
         fields[1].trim(), 
         fields[2].trim(), 
         Integer.parseInt(fields[3].trim())); 
} 

Rzucanie to wszystko razem, twoja klasa wygląda teraz tak.

public class AirportConsumer implements AirportAPI { 

    @Override 
    public Stream<Airport> getAirports() { 
     Stream<String> stream = null; 
     try { 
      stream = Files.lines(Paths.get("resources/planes.txt")) 
            .map(line -> createAirport(line)); 
     } catch (IOException e) { 
      stream = Stream.empty(); 
      e.printStackTrace(); 
     } 
     return stream; 
    } 

    private Airport createAirport(final String line) { 
     final String[] fields = line.split(";"); 
     return new Airport(fields[0].trim(), 
          fields[1].trim(), 
          fields[2].trim(), 
          Integer.parseInt(fields[3].trim())); 
    } 
} 
+0

Pod warunkiem, że 'createAirport 'metoda została zmieniona na' return' utworzonego lotniska zamiast dołączania go do tej (obecnie przestarzałej) listy. –

+1

Jako dodatek, polecam przeczytać [java.util.stream] (https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html # package.description) opis pakietu. Nie jest zbyt długie i naprawdę pomocne zrozumienie strumieni. –

+0

@tobias_k doh! Dzięki - naprawione. –

0

Kod opublikowany przez Steve wygląda świetnie. Ale wciąż można poprawić dwa miejsca: 1, Jak podzielić ciąg. 2, Może to spowodować problem, jeśli ludzie zapomną lub nie wiedzą, aby zamknąć strumień utworzony przez wywołanie metody getAirports(). Więc lepiej jest zakończyć zadanie (toList() lub cokolwiek innego) na miejscu. Oto kod przez AbacusUtil

try(Reader reader = IOUtil.createBufferedReader(file)) { 
    List<Airport> airportList = Stream.of(reader).map(line -> { 
     String[] strs = Splitter.with(";").trim(true).splitToArray(line); 
     return Airport(strs[0], strs[1], strs[2], Integer.valueOf(strs[3])); 
    }).toList(); 
} catch (IOException e) { 
    throw new RuntimeException(e); 
} 

// lub przez Try:

List<Airport> airportList = Try.stream(file).call(s -> s.map(line -> { 
    String[] strs = Splitter.with(";").trim(true).splitToArray(line); 
    return Airport(strs[0], strs[1], strs[2], Integer.valueOf(strs[3])); 
}).toList()) 

Ujawnienie: Jestem deweloperem AbacusUtil.

Powiązane problemy