2015-01-27 12 views
5

Questa domanda riguarda le apparenti importazioni "nascoste" o locali di pacchetti Java che le espressioni lambda sembrano impiegare.Le espressioni Lambda Java utilizzano le importazioni "nascoste" o di pacchetti locali?

Il seguente codice di esempio si compila e funziona bene (solo elenca i file nella directory data):

package com.mbm.stockbot; 

import java.io.IOException; 
import java.nio.file.Files; 
import java.nio.file.Paths; 

public class Temp2 { 
    public static void main(String[] args) { 
     Temp2 t = new Temp2(); 
     t.readDir(); 
    } 

    public void readDir() { 
     try { 
      Files.walk(Paths.get("C:/Users/mbmas_000/Downloads/SEC Edgar"), 1).forEach(filePath -> { 
       if (Files.isRegularFile(filePath)) { 
        System.out.println(filePath); 
       } 
      }); 
     } catch (IOException e1) { 
      e1.printStackTrace(); 
     } 
    } 
} 

nota che la variabile filePath è un'istanza di Path, la cui attuazione Credo che è contenuto nel pacchetto java.nio.file.Path, sebbene non ci sia import per quel pacchetto.

Ora, se faccio una piccola modifica, dicono dal refactoring la chiamata a System.out.println per il proprio metodo:

package com.mbm.stockbot; 

import java.io.IOException; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 

public class Temp2 { 

    public static void main(String[] args) { 
     Temp2 t = new Temp2(); 
     t.readDir(); 
    } 

    public void readDir() { 
     try { 
      Files.walk(Paths.get("C:/Users/mbmas_000/Downloads/SEC Edgar"), 1).forEach(filePath -> { 
       if (Files.isRegularFile(filePath)) { 
        printPath(filePath); 
       } 
      }); 
     } catch (IOException e1) { 
      e1.printStackTrace(); 
     } 
    } 

    public void printPath(Path passedFilePath) { 
     System.out.println(passedFilePath); 
    } 
} 

devo società 'importazione' import java.nio.file.Path, altrimenti ottengo un errore di compilazione.

Quindi le mie domande sono:

  1. Se filePath è davvero un esempio di java.nio.file.Path, perché non lo fanno ho bisogno di importarlo nel primo esempio, e

  2. Se si utilizza il espressione lambda esegue l'importazione "sotto le copertine", quindi perché do Devo aggiungere lo import quando creo un metodo che prende un'istanza di Path come argomento?

I metodi disponibili per chiamare sia filePath e passedFilePath sono identici, portandomi a credere che sono entrambe le istanze di java.nio.file.Path.

risposta

4
Le dichiarazioni

import non sono intese a dichiarare quali classi sta usando il codice; dichiarano solo cosa usare per risolvere gli identificatori non qualificati. Quindi se stai utilizzando l'identificatore non qualificato Path nel tuo codice devi usare import java.nio.file.Path; per dichiarare che dovrebbe essere risolto con questo tipo qualificato. A proposito, questo non è l'unico modo per risolvere un nome. I nomi possono anche essere risolti attraverso l'ereditarietà della classe, ad es. se corrispondono al nome semplice di una classe membro ereditata.

Se si utilizza un tipo implicitamente senza fare riferimento al nome, non è necessaria un'istruzione import, che non sia limitata alle espressioni lambda, non è nemmeno una funzionalità speciale di Java 8. Per esempio. con

Files.walk(Paths.get("C:/Users/mbmas_000/Downloads/SEC Edgar"), 1) 

si utilizza già il tipo Path implicitamente come è il tipo di ritorno di Paths.get e un tipo di parametro di Files.walk, in altre parole, si riceve un'istanza di java.nio.file.Path e passando ad un altro metodo senza riferimento a il suo nome tipo, quindi non è necessario un import. Inoltre si chiama un metodo varargs che accetta un numero arbitrario di istanze FileVisitOption. Non stai specificando nulla, quindi il tuo codice creerà un array di lunghezza zero FileVisitOption[] e lo passerà a Files.walk, ancora, senza uno import.

Con l'inferenza migliorata del tipo, esiste un'altra possibilità di utilizzare un tipo senza fare riferimento al suo nome, ad es. se si chiama:

Files.newByteChannel(path, new HashSet<>()); 

Non sei solo creando una lunghezza zero FileAttribute[] array per il parametro varargs senza fare riferimento a questo tipo in base al nome, si sta anche creando un HashSet<OpenOption> senza fare riferimento al tipo OpenOption per nome. Quindi anche questo non richiede né l'importazione di java.nio.file.attribute.FileAttribute né di java.nio.file.OpenOption.


Così la linea di fondo è, se è necessario un import non dipende l'uso del tipo, ma se si fa riferimento ad esso per la sua semplice nome (e ci sono più di un modo per utilizzare un tipo senza riferendosi ad esso per nome).Nel tuo secondo esempio ti riferisci al nome Path nel tuo metodo printPath(Path passedFilePath); se lo modifichi in printPath(Object passedFilePath), tutto funzionerà di nuovo senza un esplicito import di java.nio.file.Path.

2

La differenza è che nel secondo esempio si dichiara una variabile locale Path passedFilePath (come parametro metodo). Quando si esegue questa operazione, è necessario un import per indicare al compilatore java che tipo Path si intende, poiché più pacchetti possono avere una classe con lo stesso nome. Potresti aver notato che quando crei una variabile List something e chiedi all'IDE di creare automaticamente l'importazione, la maggior parte degli IDE ti chiederanno di solito se intendi java.util.List o java.awt.List. È inoltre possibile creare una propria classe com.myorg.myproject.List che sarebbe quindi una terza opzione.

Nel primo esempio il tipo esatto di filePath è determinato dal tipo di richiesta dal Paths.get(...).forEach, quindi non c'è bisogno di dire al compilatore Java che class Path si fa riferimento.

A proposito, è possibile omettere l'importazione nel secondo esempio, quando si riscrive la firma del metodo come public void printPath(java.nio.file.Path passedFilePath). Quando si fornisce un nome di classe completo, non è più necessario importare perché il nome della classe non può essere ambiguo.

Ci si potrebbe chiedere "ma perché è necessario un nome di importazione o completo quando esiste una sola classe denominata Path nell'intera libreria standard e non ho una propria classe con quel nome?" - ricorda che Java è progettato per la riutilizzabilità del codice. Quando il tuo codice è usato in un altro progetto, quel progetto potrebbe avere una classe simile o potrebbe usare una libreria di terze parti che ha e quindi il tuo codice sarebbe ambiguo.

+0

Dichiara una variabile 'filePath' di tipo' Percorso', questo è il punto della sua domanda. La definizione lambda con 'filePath' è di quel tipo, ma non richiede alcuna importazione. È semplicemente una sintassi opzionale in Java 8 che non richiede di scrivere il tipo 'Path' sulla definizione della variabile – Alex

+0

@Alex che ho perso. Risposta aggiornata – Philipp

0

È necessario utilizzare un'importazione nel secondo esempio perché si dichiara una variabile.

Questo non ha nulla a che fare con le espressioni lambda. Avresti esattamente la stessa cosa che succederebbe se avessi usato una classe anonima.

0

Credo che il punto che si sta cercando di illustrare può essere semplificata in questo modo:

Questo lambda richiede un'importazione

Paths.get("path").forEach((Path filePath) -> {});

Questa lambda non richiede un'importazione

Paths.get("path").forEach((filePath) -> {});

Dal Path.forEach(...) prende un Consumer<? super Path> presumo quest'ultimo caso è la creazione di un nuovo tipo di on-the-fly di ? super Path, e, quindi, non hai bisogno di un'importazione dal momento che è un nuovo tipo (come un tipo generico in fase di esecuzione)

Problemi correlati