5
\$\begingroup\$

I have this kind of file structure

MALE:FooBar:32
FEMALE:BarFoo:23

Where I would want to identify the gender and age of person, <Gender>:<Name>:<age>

try{
    BufferedReader in = new BufferedReader(new FileReader("people.ser"));
    String s;

    while((s = in.readLine()) != null){

        String[] var = s.split(":");
             //var[0]=MALE etc etc
        addGender.add(var[0]);
    }

}catch(Exception e){
    e.printStackTrace();
}
  • Is using a delimiter (like a : in this case) to split string considered a bad practice?
  • What about using the array from the splitted string to store it in some place?
  • Are there any alternatives and better file structure?
\$\endgroup\$
  • \$\begingroup\$ String.split(RegEx) is the now recommended for new Java'versions (StringTokenizer for old version compatibility). With 'palacsint' advices, you code look fine. \$\endgroup\$ – cl-r Aug 27 '12 at 8:06
8
\$\begingroup\$

I don't think that using : is a bad practice but you have to escape it somehow if it occurs inside your data. Anyway, I'd consider using XML or JSON here.

Some notes about the code:

  1. You should close the stream (in a finally block). See Guideline 1-2: Release resources in all cases in Secure Coding Guidelines for the Java Programming Language
  2. The .ser file extension is often used for serialized Java objects. I'd use something else to avoid the possible confusion.
  3. It's a good practice to set the character set when you read a text file. The used FileReader always uses the default charset which could vary from system to system. Consider using InputStreamReader and FileInputStream as the documentation of FileReader says. Here is an example:

    FileInputStream fileInputStream = null;
    InputStreamReader inputStreamReader = null;
    BufferedReader bufferedReader = null;
    try {
        fileInputStream = new FileInputStream("people.dat");
        inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
        bufferedReader = new BufferedReader(inputStreamReader);
    
        // use BufferedReader here
    } finally {
        IOUtils.closeQuietly(bufferedReader);
        IOUtils.closeQuietly(inputStreamReader);
        IOUtils.closeQuietly(fileInputStream);
    }
    

    It uses IOUtils from Apache Commons IO and closes the FileInputStream even if the constructor of InputStreamReader or BufferedReader throws an exception.

\$\endgroup\$
  • \$\begingroup\$ How would I do number 3? \$\endgroup\$ – KyelJmD Aug 26 '12 at 1:19
  • \$\begingroup\$ @KyelJmD: See the edit, please. \$\endgroup\$ – palacsint Aug 26 '12 at 1:27
  • \$\begingroup\$ why did you use final? \$\endgroup\$ – KyelJmD Aug 26 '12 at 5:39
  • \$\begingroup\$ @KyelJmD: final helps readers and maintainers, because they know that the reference always points to the same instance and it doesn't change later. programmers.stackexchange.com/questions/115690/… but you can find other questions on Programmers.SE in the topic. \$\endgroup\$ – palacsint Aug 26 '12 at 8:46
  • \$\begingroup\$ I would place those final variables in the class? or inside a method that calls them? \$\endgroup\$ – KyelJmD Aug 26 '12 at 9:50
4
\$\begingroup\$

Scanner is a bit easier to use then BufferedReader...

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;


public class Main {

    public static void main(String[] args) {        
        try {
            File f = new File("people.ser");
            Scanner sc = new Scanner(f);

            List<Person> people = new ArrayList<Person>();

            while(sc.hasNextLine()){
                String line = sc.nextLine();
                String[] details = line.split(":");
                String gender = details[0];
                String name = details[1];
                int age = Integer.parseInt(details[2]);
                Person p = new Person(gender, name, age);
                people.add(p);
            }

            for(Person p: people){
                System.out.println(p.toString());
            }

        } catch (FileNotFoundException e) {         
            e.printStackTrace();
        }
    }
}

class Person{

    private String gender;
    private String name;
    private int age;

    public Person(String gender, String name, int age){
        this.gender = gender;
        this.setName(name);
        this.age = age;
    }

    /**
     * @return the gender
     */
public String getGender() {
    return gender;
}

/**
 * @param gender the gender to set
 */
public void setGender(String gender) {
    this.gender = gender;
}

/**
 * @param name the name to set
 */
public void setName(String name) {
    this.name = name;
}

/**
 * @return the name
 */
public String getName() {
    return name;
}

/**
 * @return the age
 */
public int getAge() {
    return age;
}

/**
 * @param age the age to set
 */
public void setAge(int age) {
    this.age = age;
}

public String toString(){
    return this.gender + " " + this.name + " " + this.age;
}


}
\$\endgroup\$
  • \$\begingroup\$ toString() method should use StringBuilder instead of concatenation. \$\endgroup\$ – Eva Jan 17 '13 at 0:39
  • \$\begingroup\$ Since the toString() method is likely only used for debugging purposes, I'd say readability trumps performance here and the current implementation is a lot more readable. In case it is used in heavy iteration, that might be a different case. \$\endgroup\$ – Nihathrael Nov 25 '14 at 9:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.