2017-06-01 4 views
0

J'avais un fichier à lire et avec ce code j'ai réussi mes tests JUnit. Comme vous pouvez le voir, je passe la ligne String en paramètre à la méthode readPrevisione (...).Ligne de chaîne ou StringTokenizer avec un lecteur?

package oroscopo.persistence; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.Reader; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.HashSet; 
import java.util.List; 
import java.util.NoSuchElementException; 
import java.util.Set; 
import java.util.StringTokenizer; 

import oroscopo.model.Previsione; 
import oroscopo.model.SegnoZodiacale; 

public class TextFileOroscopoRepository implements OroscopoRepository { 

private HashMap<String, List<Previsione>> mapSettore = new HashMap<>(); 


public TextFileOroscopoRepository(Reader baseReader) throws IOException, BadFileFormatException{ 
    if (baseReader == null) 
     throw new IllegalArgumentException("baseReader is null"); 
    BufferedReader bufReader = new BufferedReader(baseReader); 
    String line; 
    while((line=bufReader.readLine()) != null){ 
     readPrevisione(line,bufReader); 
    } 



} 

private void readPrevisione(String line, BufferedReader bufReader) throws IOException, BadFileFormatException{ 
    String nomeSettore = line.trim(); 
    if (!Character.isUpperCase(nomeSettore.charAt(0))) 
     throw new BadFileFormatException(); 
    List<Previsione> listaPrev = new ArrayList<>(); 
    while (!(line = bufReader.readLine()).equalsIgnoreCase("FINE")){ 
     try{ 
     StringTokenizer st1 = new StringTokenizer(line, "\t"); 
     if(st1.countTokens() < 2) 
      throw new BadFileFormatException(); 
     String prev = st1.nextToken("\t").trim(); 
     int val = Integer.parseInt(st1.nextToken("\t").trim()); 
     Set<SegnoZodiacale> segni = new HashSet<>(); 
     if (st1.hasMoreTokens()){ 
      while(st1.hasMoreTokens()){ 
       try{ 
       segni.add(SegnoZodiacale.valueOf(st1.nextToken(",").trim())); 
       } 
       catch (IllegalArgumentException e){ 
       throw new BadFileFormatException(); 
       } 
      } 
      Previsione p = new Previsione(prev,val,segni); 
      listaPrev.add(p); 
     } 
     else{ 
      Previsione p2 = new Previsione(prev,val); 
      listaPrev.add(p2); 
     } 
     } 
     catch (NumberFormatException e){ 
      throw new BadFileFormatException(); 
     } 
     catch (NoSuchElementException e){ 
      throw new BadFileFormatException(); 
     } 

    } 
    mapSettore.put(nomeSettore, listaPrev); 
} 

@Override 
public Set<String> getSettori() { 
    return mapSettore.keySet(); 
} 

@Override 
public List<Previsione> getPrevisioni(String settore) { 
    return mapSettore.get(settore.toUpperCase()); 
    } 
} 

ici avec le même code, en passant à la place la ligne de lecture en tant que paramètre, je passe le StringTokenizer qui a déjà lu la ligne. Cela devrait fonctionner comme ci-dessus mais mes tests JUnit échouent. Qu'ai-je fait de mal?

package oroscopo.persistence; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.Reader; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.HashSet; 
import java.util.List; 
import java.util.NoSuchElementException; 
import java.util.Set; 
import java.util.StringTokenizer; 

import oroscopo.model.Previsione; 
import oroscopo.model.SegnoZodiacale; 

public class TextFileOroscopoRepository implements OroscopoRepository { 

private HashMap<String, List<Previsione>> mapSettore = new HashMap<>(); 


public TextFileOroscopoRepository(Reader baseReader) throws IOException, BadFileFormatException{ 
    if (baseReader == null) 
     throw new IllegalArgumentException("baseReader is null"); 
    BufferedReader bufReader = new BufferedReader(baseReader); 
    String line; 
    while((line=bufReader.readLine()) != null){ 
     StringTokenizer st = new StringTokenizer(line); 
     readPrevisione(st,bufReader); 
    } 



} 

private void readPrevisione(StringTokenizer st, BufferedReader bufReader) throws IOException, BadFileFormatException{ 
    String nomeSettore = st.nextToken().trim(); 
    if (!Character.isUpperCase(nomeSettore.charAt(0))) 
     throw new BadFileFormatException(); 
    List<Previsione> listaPrev = new ArrayList<>(); 
    String line; 
    while (!(line = bufReader.readLine()).equalsIgnoreCase("FINE")){ 
     try{ 
     StringTokenizer st1 = new StringTokenizer(line, "\t"); 
     if(st1.countTokens() < 2) 
      throw new BadFileFormatException(); 
     String prev = st1.nextToken("\t").trim(); 
     int val = Integer.parseInt(st1.nextToken("\t").trim()); 
     Set<SegnoZodiacale> segni = new HashSet<>(); 
     if (st1.hasMoreTokens()){ 
      while(st1.hasMoreTokens()){ 
       try{ 
       segni.add(SegnoZodiacale.valueOf(st1.nextToken(",").trim())); 
       } 
       catch (IllegalArgumentException e){ 
       throw new BadFileFormatException(); 
       } 
      } 
      Previsione p = new Previsione(prev,val,segni); 
      listaPrev.add(p); 
     } 
     else{ 
      Previsione p2 = new Previsione(prev,val); 
      listaPrev.add(p2); 
     } 
     } 
     catch (NumberFormatException e){ 
      throw new BadFileFormatException(); 
     } 
     catch (NoSuchElementException e){ 
      throw new BadFileFormatException(); 
     } 

    } 
    mapSettore.put(nomeSettore, listaPrev); 
} 

@Override 
public Set<String> getSettori() { 
    return mapSettore.keySet(); 
} 

@Override 
public List<Previsione> getPrevisioni(String settore) { 
    return mapSettore.get(settore.toUpperCase()); 
    } 

} 

EDIT: Voici le File.txt que je veux lire.

Et voici un exemple d'un de mes test JUnit:

@Test 
public void testLetturaCorrettaPrevisioni1() throws IOException, BadFileFormatException { 
    Reader mr = new StringReader(
      "NOMESEZIONE\navrai la testa un po' altrove\t\t4\tARIETE,TORO,GEMELLI\ngrande intimita'\t9\nFINE\n" 
        + "SEZIONE2\ntesto di prova\t\t\t\t\t66\t\nFINE"); 

    OroscopoRepository or = new TextFileOroscopoRepository(mr); 

    assertEquals("avrai la testa un po' altrove", or.getPrevisioni("nomesezione").get(0).getPrevisione()); 
    assertEquals(4, or.getPrevisioni("nomesezione").get(0).getValore()); 
    Set<SegnoZodiacale> validi = new HashSet<SegnoZodiacale>() { 
     private static final long serialVersionUID = 1L; 

     { 
      add(SegnoZodiacale.ARIETE); 
      add(SegnoZodiacale.TORO); 
      add(SegnoZodiacale.GEMELLI); 
     } 
    }; 
    for (SegnoZodiacale s : SegnoZodiacale.values()) { 
     if (validi.contains(s)) 
      assertTrue(or.getPrevisioni("nomesezione").get(0).validaPerSegno(s)); 
     else 
      assertFalse(or.getPrevisioni("nomesezione").get(0).validaPerSegno(s)); 
    } 

    assertEquals("grande intimita'", or.getPrevisioni("nomesezione").get(1).getPrevisione()); 
    assertEquals(9, or.getPrevisioni("nomesezione").get(1).getValore()); 
    for (SegnoZodiacale s : SegnoZodiacale.values()) { 
     assertTrue(or.getPrevisioni("nomesezione").get(1).validaPerSegno(s)); 
    } 
} 
+0

Les deux versions contiennent un NPE potentiel si 'readLine()' renvoie une valeur nulle inattendue. – EJP

+0

Si readLine() renvoie null cela signifie que le fichier file.txt est vide .. Dans la section Controller du programme (non montré ici), si le HashMap est vide, il lance une exception .. Mais de toute façon ce n'est pas le point .. Le problème est entre StringTokenizer et String transmis en tant que paramètres. – FollettoInvecchiatoJr

+0

Cela signifie que le fichier est vide * ou * ne contient pas de ligne '" FINE "'. J'ai posté cela comme un commentaire, pas une réponse. – EJP

Répondre

0

Je l'ai compris pourquoi ça n'a pas marché .. La ligne de chaîne était: "EXEMPLE \ n" mais après

while((line=bufReader.readLine()) != null){ 
...} 

line = "EXEMPLE" car readLine() mange le saut de ligne. Je transmis au readPrevisione() un StringTokenizer en tant que paramètre

while((line=bufReader.readLine()) != null){ 
    StringTokenizer st = new StringTokenizer(line); 
    readPrevisione(st,bufReader); 
} 

private void readPrevisione(StringTokenizer st, BufferedReader bufReader) throws IOException, BadFileFormatException{ 
String nomeSettore = st.nextToken().trim(); 
...} 

et recherche st.nextToken() pour une \ n qui ne figure pas dans « Exemple ». C'est pourquoi ça n'a pas marché.

0

Vous créez StringTokenizer avec séparateur par défaut, qui est « le caractère d'espace, le caractère de tabulation, le retour à la ligne, le carrossable retour caractère, et le caractère de flux de formulaire. " Donc, dans le premier cas, vous définissez la valeur de la variable "nomeSettore" sur toute la ligne, mais lorsque vous utilisez StringTokenizer.nextToken(), vous donnez à "nomeSettore" uniquement la valeur du premier jeton. Ainsi, "nomeSettore" peut avoir des valeurs différentes si votre "ligne" de chaîne contient des espaces et vous aurez différentes paires clé-valeur dans votre carte.

Vous pouvez jeter un oeil à cet exemple:

public class TestSO { 

public static void main(String[] args) { 
    String line = "abcdfs faf afd fa"; 
    StringTokenizer st = new StringTokenizer(line); 
    readPrevisione(st, null); 
    readPrevisione(line, null); 
} 

private static void readPrevisione(StringTokenizer st, BufferedReader bufReader) { 
    String nomeSettore = st.nextToken().trim(); 
    System.out.println(nomeSettore); 
} 

private static void readPrevisione(String st, BufferedReader bufReader) { 
    String nomeSettore = st.trim(); 
    System.out.println(nomeSettore); 
} 

}

Il imprime en sortie:

abcdfs 
abcdfs faf afd fa 
+0

Oui mais .. La première ligne est "EXAMPLE \ n" ... Donc je ne comprends pas l'erreur car elle devrait fonctionner avec les deux versions et le code est le même .. Change juste les paramètres String et StringTokenizer – FollettoInvecchiatoJr

+0

est votre test JUnit? Est-ce sur le contenu complet de la carte? Est-ce sur une seule ligne? Tout dépend de ce que vous testez réellement. –

+0

J'ai édité avec le fichier File.txt pour lire et le format relatif de la chaîne. – FollettoInvecchiatoJr