0
package asasaSASA;

import java.io.*;

class FileInputTest {
    public static FileInputStream f1(String fileName) {
        try {
            FileInputStream fis = new FileInputStream(fileName);
            System.out.println("f1: File input stream created");
            return fis; // I HAVE RETURN fis
        }
        catch (FileNotFoundException e) {
            System.out.println("에러는"+e);
        }
    }

    public static void main(String args[]) {
        FileInputStream fis1 = null;
        String fileName = "foo.bar";
        System.out.println("main: Starting " + FileInputTest.class.getName()
                                                   + " with file name = " + fileName);
        fis1 = f1(fileName);
        System.out.println("main: " + FileInputTest.class.getName() + " ended");
    }
}

I want to make this code run but it said

This method must return a result of type FileInputStream

I can't understand because I made return fis. Why does it say that you have to return? I already returned it!

Abra
  • 19,142
  • 7
  • 29
  • 41
김연수
  • 1
  • 1

3 Answers3

0
FileInputStream fis = new FileInputStream(fileName);

If the above line throws a FileNotFoundException then the next line of your code that will be executed is

System.out.println("에러는"+e);

which means it bypasses your return statement and that's why you are getting the compiler error.

There are many different ways to fix the compiler error and the other answers explain the different ways. I'm just answering your question, namely

Why does it say that you have to return?

I hope you understand now why you are wrong when you say

I already returned it!

Abra
  • 19,142
  • 7
  • 29
  • 41
-1

Your method throws a checked exception which must be handled either inside of the method, or outside. Checked exception are to indicate that a problem may occur and you need to implement something to handle this scenario. Here we are worried that the file does not exist.

You have three Choices:

  1. Return and handle value for not existing file (no exception is thrown here). So either return null, then check in main() that inputStream is not null, or return Optional<>, which is a JDK8 way to handle such scenarios.

Example:

 public static FileInputStream f1(String fileName) {
  try {
    FileInputStream fis = new FileInputStream(fileName);
    System.out.println("f1: File input stream created");
    return fis;
  } catch(FileNotFoundException e) {
     System.out.println("Error "+e);
     return null; // in case of not existing file
  }
 }
  1. Wrap your checked FileNotFoundException into a custom RuntimeException. This will solve your problem with compile error, but may cause problems in the future if you will not catch this exception somewhere.

Example:

 public static FileInputStream f1(String fileName) {
  try {
    FileInputStream fis = new FileInputStream(fileName);
    System.out.println("f1: File input stream created");
    return fis;
  } catch(FileNotFoundException e) {
     System.out.println("Error "+e);
     throw new RuntimeException(e);
  }
 }
  1. Instead of try-catch add this exception to your method signature:

Example:

  public static FileInputStream f1(String fileName) throws FileNotFoundException{
    FileInputStream fis = new FileInputStream(fileName);
    System.out.println("f1: File input stream created");
    return fis;

 }

But if you declare a checked exception in a method at some point you will have to catch it and handle.

Option 3 is most desired.

Beri
  • 11,470
  • 4
  • 35
  • 57
  • I would not tell a beginner to use `Optional` or anything like that -- `null` is a more basic construct that is fully legal to be returned from the OP's code method. – terrorrussia-keeps-killing Nov 16 '20 at 13:18
  • 2
    option 1 and 2 are most desired? What are you talking about. Exceptions exist for a reason, and clearly 'file is not there' is a possible but less-expected code path. Optional is for the stream API, not something you should just toss about with abandon (source: See oracle itself who cautions against overusing that), wrapping is silly here; the method is more or less called 'open a file', throwing a file-related exception type is the right move. wrapping is if 'this opens a file' is an implementation detail. – rzwitserloot Nov 16 '20 at 13:24
  • 1
    creating a custom RuntimeException is a very bad advice here – fantaghirocco Nov 16 '20 at 13:28
  • @rzwitserloot I avoid using `Optional` whenever I can in favor of using JSR-305 nullability annotations. Could you please provide a link to the Oracle document you're referring to? – terrorrussia-keeps-killing Nov 16 '20 at 13:36
  • 1
    @fluffy answer by Brian Goetz on this SO answer: https://stackoverflow.com/questions/26327957/should-java-8-getters-return-optional-type Specifically: _I think routinely using it as a return value for getters would definitely be over-use._ – rzwitserloot Nov 16 '20 at 14:13
  • 1
    @fluffy and I apologize for making an Appeal to Authority logical fallacy there, so I'll make a fair argument as well: 1. (axiomatic) Backwards compatibility is good. 2. (obvious) Optional is not backwards compatibl with nullable T (an existing 'public V get(K key)' method cannot be modified to 'public Optional'), therefore 3. (logical conclusion of 1+2) Optional cannot replace nulls in the java ecosystem. 4. (axiomatic) Mixed ways to convey not-a-result is bad, 5. (conclusion of 3+4) Optional as a general null replacement is bad. – rzwitserloot Nov 16 '20 at 14:16
-1

Your exception handling is the problem. It's common, but bad code style: Whenever you catch an exception, the right move is to either deal with that exception, or, to ensure that you (re)throw some exception.

Log it, or print it? That is not handling an exception.

In this case, 'file not found' is not something you can be expected to handle; not unless you expand on what f1 is supposed to do (tip: Methods should be a bit more descriptive than that). Thus, throwing something is fair game. Furthermore, the very definition of f1 (presumably; that name is not particular enlightening and the method has no documentation) suggests that 'open this file' is a fundamental aspect of it, and therefore, throwing a FileNotFoundException is fair as well.

Thus:

Best solution

public static FileInputStream f1(String fileName) throws IOException {
 FileInputStream fis = new FileInputStream(fileName);
 System.out.println("f1: File input stream created");
 return fis;
}

public static void main(String[] args) throws Exception {
String fileName = "foo.bar";
 System.out.println("main: Starting " + FileInputTest.class.getName()
 + " with file name = " + fileName);
 try (InputStream in = f1(fileName)) {
    // you must close any resources you open using a try-with-resources
    // construct; you did not do that in your code, I fixed this.
 }
}

NB: your psv main can (and generally should!) be declared to throws Exception.

Alternate take

This one works in any scenario where you cannot throws the exception, or if adding that the signature makes no sense because it reflects an implementation detail and not an inherent aspect of what the method is trying to do:

public static FileInputStream f1(String fileName) {
 try {
   FileInputStream fis = new FileInputStream(fileName);
   System.out.println("f1: File input stream created");
   return fis;
 } catch (IOException e) {
   throw new RuntimeException("Unhandled", e);
 }
}

Naturally, this is only appropriate for situations where you really don't expect that exception to occur under normal circumstances. Otherwise, either throw that exception onwards or make your own exception type and throw that instead of RuntimeException.

If you just need a ¯\(ツ)/¯ I don't really know what this means, I just want to move on and get rid of these exceptions solution: throw new RuntimeException("Uncaught", e); is correct; e.printStackTrace(); is incorrect. Update your IDE's templates.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72