在Java中避免使用多个If语句

时间:2009-08-19 09:11:54

标签: java

我编写了一个像这样的方法。但我想这应该进行重构。 任何人都可以建议避免使用这多个if语句的最佳方法吗?

private String getMimeType(String fileName){
  if(fileName == null) {
    return "";   
  } 
  if(fileName.endsWith(".pdf")) {
    return "application/pdf";   
  }
  if(fileName.endsWith(".doc")) {
    return "application/msword";  
  }
  if(fileName.endsWith(".xls")) {
    return "application/vnd.ms-excel"; 
  }
  if(fileName.endsWith(".xlw")) {
    return "application/vnd.ms-excel"; 
  }
  if(fileName.endsWith(".ppt")) {
    return "application/vnd.ms-powerpoint"; 
  }
  if(fileName.endsWith(".mdb")) {
    return "application/x-msaccess"; 
  }
  if(fileName.endsWith(".rtf")) {
    return "application/rtf"; 
  }
  if(fileName.endsWith(".txt")) {
    return "txt/plain"; 
  }
  if(fileName.endsWith(".htm") || fileName.endsWith(".html")) {
    return "txt/html"; 
  }
  return "txt/plain"; 
}

我不能在这里使用switch-case,因为我的'条件'是java.lang.String

13 个答案:

答案 0 :(得分:34)

您可以使用Map来解决问题:

Map<String,String> extensionToMimeType = new HashMap<String,String>();
extensionToMimeType.put("pdf", "application/pdf");
extensionToMimeType.put("doc", "application/msword");
// and the rest

int lastDot = fileName.lastIndexOf(".");
String mimeType;
if (lastDot==-1) {
    mimeType = NO_EXTENSION_MIME_TYPE;
} else {
    String extension = fileName.substring(lastDot+1);
    mimeType = extensionToMimeType.get(extension);
    if (mimeType == null) {
        mimeType = UNKNOWN_EXTENSION_MIME_TYPE;
    }
}

要使此代码有效,您需要在课堂上定义NO_EXTENSION_MIME_TYPEUNKNOWN_EXTENSION_MIME_TYPE,有点像这样:

private static final String NO_EXTENSION_MIME_TYPE = "application/octet-stream";
private static final String UNKNOWN_EXTENSION_MIME_TYPE = "text/plain";

答案 1 :(得分:11)

或许使用HashMap

这样你就可以myMap.get(mystr);

答案 2 :(得分:4)

我个人对if语句没有问题。代码是可读的,只需几毫秒即可理解您正在做的事情。无论如何,这是一个私有方法,如果mime类型列表是静态的,那么就没有迫切需要将映射移动到属性文件并使用查找表(map)。 Map会减少代码行,但要理解代码,那么你就不得不阅读代码和映射的实现 - 无论是静态初始化器还是外部文件。

可以稍微更改代码并使用枚举:

private enum FileExtension { NONE, DEFAULT, PDF, DOC, XLS /* ... */ }

private String getMimeType(String fileName){
  String mimeType = null;

  FileExtension fileNameExtension = getFileNameExtension(fileName);

  switch(fileNameExtension) {
    case NONE:
      return "";
    case PDF:
      return "application/pdf";

    // ...

    case DEFAULT:
      return "txt/plain";   
  }

  throw new RuntimeException("Unhandled FileExtension detected");
} 

getFileNameExtension(String fileName)方法只返回fileName的拟合枚举值,FileExtension.NONE如果fileName为空(或null?)和FileExtension.DEFAULT,如果文件扩展名未映射到a哑剧型。

答案 3 :(得分:4)

使用 MIME检测库呢?

  • mime-util
  • mime4j
  • JMimeMagic库 - 免费。使用文件扩展名和魔术标头来确定MIME类型。
  • mime-util - 免费。使用文件扩展名和魔术标头来确定MIME类型。
  • DROID(数字记录对象识别) - 免费。使用批处理自动化来检测MIME类型。
  • Aperture Framework - 免费。用于抓取外部源以识别MIME类型的框架。

(随意添加更多,有这么多的库..)

答案 4 :(得分:2)

我认为你的方法是最好的整体。在我自己测试了许多不同的方法之后。

我认为您当前的方法有很多好处,即:

  1. 任何人都很容易可读和易懂(根据我的经验,中级程序员经常低估这一点,而且通常更喜欢使用花哨模式,最终对于绝大多数人来说根本不可读那些不了解特定模式的程序员)
  2. 所有信息都在一个地方。正如安德烈亚斯指出的那样,在你度假期间需要修复错误的人不适合搜索文件或类别!
  3. 轻松可维护:我可以在方法上“F3”(如果您正在使用Eclipse)并在几秒钟内添加新的内容类型,而无需担心引入错误!
  4. 无论如何,我可以提出一些建议:

    1. 此方法非常通用: 为什么要私密?!这是一个 一些实用程序/帮助程序类的公共方法! 而且它应该是一个静态方法 !!你不需要任何东西 从Object本身来执行 你的工作!
    2. 您可以使用缩进制作 东西更漂亮,更紧凑。我知道 缩进是某种形式 我们大多数人的宗教,但我 认为它不应该是一个严格的规则; 它应该适当地用于制作 我们的代码更强可读且紧凑。 如果这是一个配置文件你 可能会有类似的东西:
    3. pdf=application/pdf
      doc=application/msword
      

      你可以得到一个非常相似的结果:

          public static String getMimeType(String fileName){
             if(fileName == null) return "";
             if(fileName.endsWith(".pdf")) return "application/pdf";
             if(fileName.endsWith(".doc")) return "application/msword";
             if(fileName.endsWith(".xls")) return "application/vnd.ms-excel"; 
             return "txt/plain"; 
         }
      

      这也是许多基于地图的实现的样子。

答案 5 :(得分:2)

命令模式是要走的路。以下是使用java 8的一个示例:

<强> 1。定义界面:

public interface ExtensionHandler {
  boolean isMatched(String fileName);
  String handle(String fileName);
}

<强> 2。使用每个扩展程序实现界面:

public class PdfHandler implements ExtensionHandler {
  @Override
  public boolean isMatched(String fileName) {
    return fileName.endsWith(".pdf");
  }

  @Override
  public String handle(String fileName) {
    return "application/pdf";
  }
}

public class TxtHandler implements ExtensionHandler {
  @Override public boolean isMatched(String fileName) {
    return fileName.endsWith(".txt");
  }

  @Override public String handle(String fileName) {
    return "txt/plain";
  }
}

依旧.....

第3。定义客户端:

public class MimeTypeGetter {
  private List<ExtensionHandler> extensionHandlers;
  private ExtensionHandler plainTextHandler;

  public MimeTypeGetter() {
    extensionHandlers = new ArrayList<>();

    extensionHandlers.add(new PdfHandler());
    extensionHandlers.add(new DocHandler());
    extensionHandlers.add(new XlsHandler());

    // and so on

    plainTextHandler = new PlainTextHandler();
    extensionHandlers.add(plainTextHandler);
  }

  public String getMimeType(String fileExtension) {
    return extensionHandlers.stream()
      .filter(handler -> handler.isMatched(fileExtension))
      .findFirst()
      .orElse(plainTextHandler)
      .handle(fileExtension);
  }
}

<强> 4。这是样本结果:

  public static void main(String[] args) {
    MimeTypeGetter mimeTypeGetter = new MimeTypeGetter();

    System.out.println(mimeTypeGetter.getMimeType("test.pdf")); // application/pdf
    System.out.println(mimeTypeGetter.getMimeType("hello.txt")); // txt/plain
    System.out.println(mimeTypeGetter.getMimeType("my presentation.ppt")); // "application/vnd.ms-powerpoint"
  }

答案 6 :(得分:1)

总的来说,没有办法逃避这种情况。在你的情况下 - 如果有一组允许的扩展名 - 你可以创建一个枚举,通过valueOf()将扩展名转换为枚举类型,然后你可以切换你的枚举。

答案 7 :(得分:1)

我会通过将关联放在地图中,然后使用地图进行查找来完成此操作:

Map<String, String> map = new HashMap<String, String>();

map.put(".pdf", "application/pdf");
map.put(".doc", "application/msword");
// ... etc.

// For lookup:
private String getMimeType(String fileName) {
    if (fileName == null || fileName.length() < 4) {
        return null;
    }

    return map.get(fileName.substring(fileName.length() - 4));
}

请注意,在字符串上使用switch语句是下一版Java的新功能之一;有关更多详细信息,请参阅this page以及Java 7中的外观示例:

switch (fileName.substring(fileName.length() - 4)) {
    case ".pdf": return "application/pdf";
    case ".doc": return "application/msword";
    // ...
    default: return null;

(编辑:我的解决方案假定文件扩展名总是3个字母;如果它可以更长或更短,则必须稍微更改它。)

答案 8 :(得分:1)

这个特定问题的最简单和最简单的方法是使用内置的Java SE或EE方法。

在“普通的vanilla”客户端应用程序中(从底层平台获取此信息):

String mimeType = URLConnection.guessContentTypeFromName(filename);

或者在JSP / Servlet Web应用程序中(从web.xml文件中获取此信息):

String mimeType = getServletContext().getMimeType(filename);

答案 9 :(得分:0)

你总是可以在这里使用Groovy类,因为它允许在字符串上使用switch-case:)

答案 10 :(得分:0)

如何将扩展名映射到MIME类型,然后使用循环?类似的东西:

Map<String,String> suffixMappings = new HashMap<String,String>();
suffixMappings.put(".pdf", "application/pdf");
...

private String getMimeType(String fileName){
    if (fileName == null) {
        return "";   
    }
    String suffix = fileName.substring(fileName.lastIndexOf('.'));
    // If fileName might not have extension, check for that above!
    String mimeType = suffixMappings.get(suffix); 
    return mimeType == null ? "text/plain" : mimeType;
 } 

答案 11 :(得分:0)

创建一个名为MimeType的枚举,其中包含2个String变量:extension和type。创建一个适当的构造函数并传入“.xxx”和“application / xxx”值。创建一个方法来执行查找。您可以在开关中使用枚举。

答案 12 :(得分:0)

提一下:直接等同于你的代码不会使用地图进行直接查找(因为这需要每个扩展名正好有3个字符),而是for循环:

...
Map<String, String> extmap = GetExtensionMap();
for (Map.Entry<String,String> entry: extmap.entrySet())
  if (fileName.endsWith(entry.getKey))
    return entry.getValue();
...

此解决方案适用于任何长度的扩展,但当然不如哈希查找(并且性能略低于原始解决方案)

Algorithmic-Design-Guy解决方案

更高效的方法是实现从扩展的 last 字符开始的树结构,并在相应的节点上存储适当的MIME类型。 然后,您可以从文件名的最后一个字符开始向下走树。但这可能是一种矫枉过正......