IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

[Constructeur / Champs] Pb Valeurs null


Sujet :

Langage Java

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut [Constructeur / Champs] Pb Valeurs null
    Bonjour,

    J'ai un petit problème d'initialisation de champs dans une classe, et j'aimerais savoir ce que je fais de mal

    Pour extrait les deux classes utilisées :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class Accord extends Donnees {
      //Un champ de classe
      private ArrayList champ = null;
     
      //Constructeur
      public Accord(String[] champs){
        super(champs);
      }
     
      //Méthode appelée par la classe mère
      public void setChamps(){
        // Faute corrigée
        this.champ = new ArrayList();
        this.champ.add("Test");
      }
     
      //Retourne la liste
      public ArrayList getListeChamp(){
        return this.champ;
      }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    abstract public class Donnees {
      //Constructeur
      public Donnees(String[] champs){
        this.setChamps();
      }
     
      //Méthode abstract
      abstract public void setChamps();
    }
    Le problème est qu'après instanciation, l'ArrayList "champs" est null :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Accord obj = new Accord(blabla);
    ArrayList uneListe = obj.getListeChamp();
    //uneListe est null
    En remplaçant "private ArrayList champ = null;" par "private ArrayList champ;", ça marche, mais je m'inquiète car je fais cette définition très souvent (ou "private ArrayList champ = new ArrayList();", et ça m'inquiète de ne pas avoir rencontré ce problème plus tôt.
    Ai-je vraiment de quoi m'inquiéter, ou y-a-t-il quelque chose que je fais mal ?

    Quels seraient les risques à remplacer toutes ces déclarations ("private ArrayList champ = null;" par "private ArrayList champ;") ?

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    802
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 802
    Par défaut
    Je tiens à te faire remarqué que le code que tu as posté contient de nombreuses erreurs et ne compile pas. Donc si tu fais autant d'étourderies en développant ton application qu'en postant sur ce forum, cela expliquerait les erreurs que tu rencontres

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Erf oui c'est sur

    Je pense plus à des erreurs lors du post, où j'ai réécri l'exemple plutot que de copier/coller. J'corrige les erreurs tout de suite ^^

    [Edit] C'est mieux là ? Pas facile d'écrire du java sans éditeur J'aurais été plus vite à copier/coller depuis Eclipse, mais bon. Manque de café on dira !

  4. #4
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      //Méthode appelée par la classe mère
      public void setChamps(){
        this.champs = new ArrayList();
        this.champs.add("Test");
      }
    // ....
      public ArrayList getListeChamp(){
        return this.champ;
      }
    Visiblement, t'as deux fields: champ et champs

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Bon, je copie le code réel lol :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    public class MNAccords extends NDonneesBase {
     
    	/** ArrayList d'objets Versement lié à l'accord. Null si la caisse n'est pas de type versement. */
    	private ArrayList versements = null;
     
    	/** Constructeur : A partir d'une liste de colonnes et de leurs valeurs.
             */
    	public MNAccords(String[] cols, Object[] vals) {
    		super(cols,vals);
    	}
     
    	/** Surcharge de setDonnée
             */
    	protected void setDonnée(String nomCol, Object valeur) {
    		try {
    			/* unTest est une méthode qu'il est inutile de détailler pour le problème en question */
    			if ( unTest )
    				this.chargerVersements();
    		}
    		catch (NLectureException e) {
    			e.afficher();
    		}
    	}
     
    	/** Charge les montants versés stockés dans la base.
             * @throws NLectureException : En cas d'erreur lors de la sélection des versements.
             */
    	private void chargerVersements() throws NLectureException {
    		NBaseSelect sel = new NBaseSelect(tVERSEMENT,new NCleMultiple("IDAccord",this.getIdentifiant()));
    		sel.setOrderBy(new String[] {cPERIODE,cDATE});
    		sel.exécuter();
    		while ( sel.hasNext() ) {
    			// Si versements est null, on l'initialise
    			if ( versements == null )
    				versements = new ArrayList();
    			Versement donnée = new Versement(sel.getColonnes(), sel.getLigneTO());
    			versements.add(donnée);
    		}
    		sel.close();
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public abstract class NDonneesBase {
     
    	/** HashMap des valeurs de la donnée en cours */
    	private HashMap valeurs = new HashMap();
     
    	 /** Constructeur : A partir des colonnes et des valeurs de l'instance en cours.
             */
    	protected NDonneesBase(String[] cols, Object[] vals) {
    		for ( int i = 0; cols != null && i < cols.length; i++ )
    			this.setValeur(cols[i],vals[i]);
    	}
     
    	/** Définition de la valeur d'une colonne.
             */
    	public void setValeur(String nomCol, Object valeur) {
    		valeurs.put(nomCol, valeur);
    		this.setDonnée(nomCol, valeur);
    	}
     
    	/** Définition d'une donnée liée à la valeur d'une colonne. */
    	abstract protected void setDonnée(String nomCol, Object valeur);
    L'enchainement est un peu moins simple à comprendre, mais bon.
    Le problème concerne uniquement l'ArrayList versements (ou l'ArrayList champ dans le premier exemple simplifié) qui est null après instanciation.

    Quand je passe en debug la construction d'un objet (MNAccords obj = new MNAccords(cols,vals); ), l'ArrayList est bien construite. Mais apres, une fois l'instruction passée, le champ repasse à null.
    Apparement, ce serait parcequ'après le construction, il y a initialisation des champs de classe. Du coup, si je mets "private ArrayList versements;" au lieu de "private ArrayList versements = null;", ça marche.
    Ou alors, je change le constructeur en faisant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    	/** Constructeur : A partir d'une liste de colonnes et de leurs valeurs.
             */
    	public MNAccords(String[] cols, Object[] vals) {
    		super(cols,vals);
    		if (unTest)
    			this.chargerVersement();
    	}
    }
    Mais la première possibilité m'embete un peu, car desfois il faut initialiser les champs, desfois non. Et pour la deuxième : quel est l'avantage de déclarer des methodes à partir du constructeur si à la fin de celui les champs sont "réinitialisés" ?

    J'ai un peu le même problème dans une sous-classe (la classe Versement notament), où MNAccords.this est null tant que le constructeur n'est pas "terminé" .

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    802
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 802
    Par défaut
    Je ne vois pas l'origine de l'erreur, mais je peux t'assurer une chose :
    faire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ArrayList versements = null;
    et faire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ArrayList versements;
    revient strictement au même.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Et ben apparement non

    En mode debug sur eclipse, voici ce qu'il se passe lors de l'instruction "new MNAccords(cols,vals);" :

    Passage dans MNAccords.MNAccords(String[] cols,Object[] vals) (le constructeur). Appelle super(cols,vals).
    Passsage dans NDonneesBase.NDonneesBase(String[] cols,Object[] vals) (constructeur). Chaque boucle appelle setValeur(String col, Object val).
    Passage dans NDonneesBase.setValeur(String col, Object val). Appelle la méthode abstract setDonnée(String col, Object val).
    Passage dans MNAccords.setDonnée(String col, Object val). Si le test répond 'true', appelle la méthode setVersement().
    Passage dans MNAccords.setVersement(). Rempli l'ArrayList "versement". Elle est donc non nulle.
    Fin du constructeur NDonneesBase.
    Fin de l'instruction super() dans le constructeur MNAccords.
    Initialisation des champs de classe. Là, avec "ArrayList versements = null;", l'ArrayList est remise à null. Avec "ArrayList versements;", elle n'est pas touchée, et donc n'est pas null.
    Fin du constructeur MNAccords.

    La seconde solution serait d'insérer entre "Fin de l'instruction super() dans le constructeur MNAccords." (et donc l'initialisation) et "Fin du constructeur MNAccords." l'appel à la méthode setVersement.

    Mais je trouve pas celà très propre, puisque soit je ne mets pas les champs à null, soit je dois ajouter des instructions spécifiques dans le constructeur de chaque classe héritant de NDonneesBase.

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    802
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 802
    Par défaut
    Alors je viens de tester ton code, et effectivement, il y une cou*** dans le pâté

    Voici le code que j'ai testé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    public class SuperClasse extends SousClasse {
    	private ArrayList list = null;
     
    	public SuperClasse() {
    		super();
    	}
    	@Override
    	public void setList() {
    		if(list == null)
    			list = new ArrayList();
    	}
    	public ArrayList getList() {
    		return list;
    	}
    }
     
    public abstract class SousClasse {
    	protected SousClasse() {
    		setList();
    	}
    	public abstract void setList();
    }
    Je n'avais jamais rencontré cette situation, mais cela confirme deux points que je préconise systématiquement à mes stagiaires, à savoir éviter d'appeler une méthode non static dans un constructeur et initialiser les attributs dans le constructeur plutôt qu'au moment de leur déclaration.

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    C'est bien ce que je pensais. Si les solutions ne m'arrangent pas, je n'ai pas trop le choix.

    Là où ça se complique un peu, c'est lorsque l'objet peut être null à l'instanciation (une liste qui ne serait remplie que si nécessaire). J'ai donc dans la méthode get une sécurité :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public ArrayList getListe(){
      // Si la liste est null, on la charge
      if ( this.liste == null )
        this.chargerListe();
      return this.liste;
    }
    Mais ce qui m'inquiétais en début de post, c'est la déclaration de la liste. Avant, dans beaucoup de classes, je faisais "private Object monObjet = null;" ou "private Object monObjet = new [...];". Et je testais donc lorsque j'en avais besoin, si "monObjet" était null. Dans mon cas, l'ArrayList versement était donc chargé au moins 2 fois (dans le constructeur, puis à cause de la cou***). Celà m'oblige à revenir sur le reste du projet, mais bon, tant pis.
    Par contre, lorsque les champs sont des types primitifs, là je suis coincé : Je peux pas faire "if ( champ == null )" lorsque champ est un boolean, int ou autre. Comment puis-je faire dans ce cas ?

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    802
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 802
    Par défaut
    Bah tu testes avec la valeur par défaut des primitives (je ne suis pas sûr d'avoir bien compris ton problème) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int i;
    if(i == 0) {
    	[...]
    }
     
    boolean b;
    if(! b) {
    	[...]
    }

  11. #11
    Membre émérite

    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    510
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 510
    Par défaut
    je pense que tu dois définir un valeur par défault a ton booléen... une valeur qui entrainerai un test supplémentaire par exemple, j'ai eu a faire ca a cause de la réponse d'un composant électronique :

    si je recevais un 1 j'avais un bloc d'instruction a executer : pas de probleme.
    si c'étais un zéro je devais vérifier un parametre lanmbda, si c'étais bon un bloc a exécuter sinon une sortie d'appli avec retour d'erreur.

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Moué. Mais dans ce cas, je ne sais pas si la valeur a été calculé ou non (ou alors il faut que j'ajoute d'autres flags, mais on s'en sort plus !).

    Vu le nombre de classe que j'ai, est ce que je peux faire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    public class SuperClasse extends SousClasse {
    	private ArrayList list = null;
     
    	public SuperClasse() {
    		super();
    		// Instruction obligatoire
    		super.setValeurs();
    	}
    	@Override
    	public void setList() {
    		if(list == null)
    			list = new ArrayList();
    	}
    	public ArrayList getList() {
    		return list;
    	}
    }
     
    public abstract class SousClasse {
    	protected SousClasse() {
    		// Suppression de l'appel dans le constructeur principal
    		//setList();
    	}
    	protected final void setValeurs(){
    		this.setList();
    	}
    	public abstract void setList();
    }
    Ce code marche (sauf fautes de frappe), puisque du coup la méthode est appelé après construction de l'objet SuperClasse et non SousClasse. C'est d'ailleur ce que je faisais dans des anciennes classes lorsque j'apprenais le langage (je viens de voir que j'ai déjà eu ce problème)

    Seulement, y-a-t-il un moyen de garantir l'appel à "super.setValeurs()" (que j'appelais avant "initialiserAprèsConstructeur" d'ailleur) ? Parceque si je l'oublie dans une des classes héritières, le système tombe à l'eau

  13. #13
    Membre émérite

    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    510
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 510
    Par défaut
    et bien oui

    imaginons que tu "observe" la classe ou se trouve ta méthode et que tu ajoute un observer dans les classes héritieres...

    il te suffirait de vérifier que tu passe bien dans la méthode update de tes classe héritiere pour etre sur d'etre passé par ta méthode setValeur().

    je n'ai pas testé mais je pense que ca peut marcher

  14. #14
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Je n'ai pas compris. Tu veux dire manuellement, ou à l'exécution du programme (en envoyant une exception si la méthode est absente) ? Je pense que par Eclipse, ce n'est pas possible ?

  15. #15
    Membre émérite

    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    510
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 510
    Par défaut
    mais non ce que tu veux faire clairement c'est savoir si tu passe bien par la méthode setValeur() c'est bien ca ?

    alors tu étends ta classe de cette méthode a la classe Observable;

    partout ou tu veux passer tu mets :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    setChangerd();
    notifyObservers();
    et tu implemente les classes qui doivent le vérifier par la classe Observer
    ensuite tu ajoute a ces classes les observable :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    classeAObserver.addObserver(this);
    et voila.

  16. #16
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Ha d'accord. Je ne connaissais pas. Je regarde ça, je teste, et j'reviens lundi

    Merci !

  17. #17
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    802
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 802
    Par défaut
    Personnellement, je te conseillerais plutôt quelque chose comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    public abstract class NDonneesBase {
    	private HashMap valeurs = new HashMap();
     
    	protected NDonneesBase() {
     
    	}
     
    	public void setValeur(String[] cols, Object[] vals) {
    		for ( int i = 0; cols != null && i < cols.length; i++ )
    			this.setValeur(cols[i],vals[i]);
    	}
     
    	public void setValeur(String nomCol, Object valeur) {
    		valeurs.put(nomCol, valeur);
    		this.setDonnée(nomCol, valeur);
    	}
     
    	abstract protected void setDonnée(String nomCol, Object valeur);
    }

  18. #18
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    C'est ce que je pense faire. Mais il faudrait garantir que toutes les classes qui étendent NDonneesBase appellent bien super.setValeur(String[],Object[]) !

    Nolofinwe :
    Je ne vois pas où mettre le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    setChangerd();
    notifyObservers();
    Dans le constructeur, là où je veux garantir d'appeler la bonne méthode ? Si c'est le cas, quit à penser ajouter ces lignes, autant ajouter la méthode à appeler

  19. #19
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    bon, il est tard je répond vite fait.

    Ton problème est que le constructeur super fait appel à une méthode du child qui elle meme manipule un champ du child. Hors, si on suit le chainage des constructeurs en java, le constructeur du parent est toujours exécuté avant celui de l'enfant. Résultat, dans le constructeur du parent, tu retourne vers une méthode de l'enfant qui initialise un truc, puis, dans cette même méthode, tu joue avec un field non initialisé (car son initialisation aura lieu dans le constructeur enfant). Résultat, quand le constructeur enfant est appelé, il met ton arraylist à null.

  20. #20
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Oui, c'est ce que je dis dans un de mes posts précédents.
    Maintenant, le problème, c'est de savoir où j'ai fais ce genre d'erreur, pour les corriger. Les plus flagrants déclenchent des NullPointerException, mais beaucoup ne le font pas.

    Je met le tag résolue en attendant la réponse de nolofinwe.

    Merci à tous !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] Entity Framework et les champs de valeur null
    Par wstboss71 dans le forum C#
    Réponses: 0
    Dernier message: 26/10/2011, 11h34
  2. [MySQL] problème update champ float valeur null
    Par dubitoph dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 25/02/2009, 12h42
  3. Réponses: 2
    Dernier message: 06/02/2008, 23h14
  4. [CR] Ne pas afficher un champ de valeur nulle
    Par mavericks dans le forum SAP Crystal Reports
    Réponses: 4
    Dernier message: 28/03/2007, 17h06
  5. Selectionner un champ de valeur nulle
    Par arcane dans le forum Requêtes
    Réponses: 2
    Dernier message: 30/09/2003, 15h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo