2013-10-15 1 views
1

En utilisant java-8 maintenant j'ai tourné une déclaration explicite dans une expression lambda et ai obtenu une erreur de compilateur. Donc, je suppose qu'il s'agit d'un "bug" de la version actuelle de java-8 (b105).Java-8 lambda fonctionnelle vs expression explicite signale une erreur de compilateur

L'exemple de code définit deux objets Function avec et sans utiliser une expression lambda. Les deux relais sur un prédicat qui est utilisé par ces fonctions. Alors que la mise en œuvre traditionnelle fonctionne, la version lambda signale une erreur:

java: variable fileExists might not have been initialized

Ce n'est pas tout à fait tort, mais le prédicat est pertinent si la fonction est utilisée pas si la fonction elle-même est créée (depuis la version explicite fonctionne bien). Dois-je signaler un bug (quelqu'un a un lien?) Ou ai-je oublié quelque chose?

public class FileOpener { 

public FileOpener(Predicate<File> fileExists) { 
    this.fileExists = fileExists; 
} 

final Predicate<File> fileExists; 

final Function<File, FileInputStream> openLambda = file -> { 
    try { 
     return fileExists.test(file) ? new FileInputStream(file) : null; 
    } catch (FileNotFoundException e) { 
     throw new RuntimeException(e); 
    } 
}; 

// this version compiles 
final Function<File, FileInputStream> openFunction = new Function<File, FileInputStream>() { 
    @Override 
    public FileInputStream apply(File file) { 
     try { 
      return fileExists.test(file) ? new FileInputStream(file) : null; 
     } catch (FileNotFoundException e) { 
      throw new RuntimeException(e); 
     } 
    } 
}; 

}

+0

Avant de signaler un bug je (a) passer à la dernière version et (b) demander sur la liste de diffusion dédiée, peut-être celui-ci: http://mail.openjdk.java.net/mailman/listinfo/jdk8-dev Le comportement pour le lambda semble raisonnable car c'est un lambda capturant et il a probablement besoin de connaître sa valeur de paramètre quand elle est construite. – assylias

+0

Et où 'fileExists' est-il initialisé? Les champs ne sont-ils pas initialisés avant le constructeur? –

+0

@assylias: "capturer" s'applique uniquement aux variables locales. Comme ce n'est pas dans une méthode, il n'y a pas de variables locales. – newacct

Répondre

0

J'ai essayé votre code et joué avec un peu ... Il s'avère, si vous supprimez le modificateur final de fileExists, tout est compilé et fonctionne très bien, peut-être la discussion dans les commentaires est pas 100% précis, fileExists peut effectivement être initialisé dans le constructeur. On dirait que le compilateur ne détecte pas que l'initialisation se passe réellement (ummm?).

Cela peut être un bug ... La seule chose pour les bogues que j'ai trouvé est http://bugreport.sun.com/bugreport/ (malgré le nom de Sun, conduit effectivement au site Oracle).

P.S .: J'utilise B111 d'Octobre, 10.

1

Le message d'erreur est correct comme cela a été souligné par Edwin Dalorzo. L'ordre d'initialisation est important ici. Les initialiseurs de champ sont d'abord exécutés dans l'ordre d'apparition dans le fichier source, puis dans le constructeur. Lambda référençant les variables capture les variables et dans le cas des variables finales (et toutes les variables locales) capturent la valeur réelle de la variable qui nécessite l'initialisation de la variable. Cela est conforme à la spécification du langage Java et n'a pas changé en Java 8:

class SimpleTest 
{ 
    SimpleTest() 
    { 
    first="a string"; 
    } 
    final String first; 
    String second=first; 
} 

montre exactement le même comportement dans la version avant Java 8.

+0

Le remède serait d'initialiser openLambda aussi dans le constructeur --- il n'y a aucune raison de ne pas le faire, mais il * semble * un peu maladroit. – Ingo

+0

C'est vrai. L'alternative serait de supprimer le modificateur 'final'. Mais je préférerais toujours garder le dernier modificateur et initialiser dans le constructeur. – Holger

+0

Je ne pense pas que cette réponse soit correcte.Les Lambdas ne "capturent" que des variables locales. Les variables d'instance sont accessibles via la référence de classe externe et ne sont pas capturées. – user102008