简体   繁体   中英

how to create java generic method which returns String or ArrayList<String>

As a part of self-improvement, I'm practising generics in java, and I have a case - It's just a learning case - not a real-world scenario... I'm trying to write a generic method which takes a string as an argument and based on return type it should return either String or List.

In the normal (easy logic) situation I've done like that:

public class ConfigFile{

    String fileName;

    public ConfigFile(String filename) {
        this.fileName = filename;
    }

    public String getFilename() {
        return fileName;
    }

    public String readFileAndReturnString() {
        String content = "";
        try {
            BufferedReader br = new BufferedReader(new FileReader(new File(this.fileName)));
            String line;

            while ((line = br.readLine()) != null) {
                content = content.concat(line + "\n");
            }
        } catch (IOException e) {
            System.out.println("== IO exception");
            e.printStackTrace();
        }
        return content;

    }

    public ArrayList<String> readFileAndReturnStringArr(String filename) {
        List<String> content = new ArrayList<>();
        try {
            BufferedReader br = new BufferedReader(new FileReader(new File(this.fileName)));
            String line;

            while ((line = br.readLine()) != null) {
                content.add(line);
            }
        } catch (IOException e) {
            System.out.println("== IO exception");
            e.printStackTrace();
        }
        return content;
    }
}

I can test them easily:

...
@Test
public void printStringTest() {
    String someStrFile = configFile.readFileAndReturnString();  
    System.out.println(String.format("==== str: %s", someStrFile));
}
    
@Test
public void printArrayTest() {
    ArrayList<String> someArrFile = configFile.readFileAndReturnStringArr();
    for (String line : someArrFile) {
        System.out.println(String.format("arr: %s", line));
    }
}
...

Now i would like to make a generic method which would merge logic from both of methods and i'can't figure out how can I achieve this (if it's even possible)

    public <T> T readTheFile() {
   //     ...implementation
    }

to use it like this:

ConfigFile someConfFile = new ConfigFile("C:\\temp\\someFile.txt");
String strConfFile = someConfFile.readTheFile(); //to return here String
ArrayList<String> arrConfFile = someConfFile.readTheFile(); //to return here ArrayList<String>

I've tried few things but I failed. Can you please help me figure out that? Or maybe there is some other solution for such case or maybe it totally doesn't make sense

Thanks in advance

You don't really have to use generics, but simply extract the common code you have into another method (adapted the code slighty to use modern idioms):

public void readFileInto(Consumer<? super String> accumulator) {
    try(BufferedReader br = new BufferedReader(new FileReader(new File(this.fileName)))) {
        
        String line;
        while ((line = br.readLine()) != null) {
            accumulator.accept(line);
        }
    } catch (IOException e) {
        throw new UncheckedIOException(e);
    }
}

Which the two other methods then can delegate to:

public String readFileAndReturnString() {
    StringBuilder sb = new StringBuilder();
    readFileInto(sb::append);
    return sb.toString();
}

public ArrayList<String> readFileAndReturnStringArr(String filename) {
    ArrayList<String> list = new ArrayList<>();
    readFileInto(list::add);
    return list;
}

If you are not wise in the arts of lambdas and method references which look like this:

  • foo -> bar(foo)
  • this::bar
  • Baz::bar

Then I suggest reading the following article: Lambda expressions

You should use standard library API in java.nio.Files like this.

public String readFileAndReturnString() throws IOException {
    return Files.readString(Paths.get(this.fileName));
}

public List<String> readFileAndReturnStringArr() throws IOException {
    return Files.readAllLines(Paths.get(this.fileName));
}

It's a bad design to return an empty string or empty list when an IOException is thrown. Because you cannot distinguish from reading an empty file. You should explicitly throw back the IOException .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM