避免在 Java 中使用多个 If 语句
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1298672/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Avoiding multiple If statements in Java
提问by jai
I've coded a method something like this. But I guess this should undergo refactoring. Can any one suggest the best approach to avoid using this multiple if statements?
我已经编写了一个类似这样的方法。但我想这应该进行重构。任何人都可以建议避免使用多个 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";
}
I cannot use switch-case here as my 'condition' is a java.lang.String.
我不能在这里使用 switch-case,因为我的“条件”是java.lang.String.
回答by Joachim Sauer
You can use a Mapto hold your solutions:
您可以使用 aMap来保存您的解决方案:
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;
}
}
For this code to work you'll need to have defined NO_EXTENSION_MIME_TYPEand UNKNOWN_EXTENSION_MIME_TYPEas in your class, somewhat like this:
要使此代码正常工作,您需要像在类中一样定义NO_EXTENSION_MIME_TYPE和UNKNOWN_EXTENSION_MIME_TYPE,有点像这样:
private static final String NO_EXTENSION_MIME_TYPE = "application/octet-stream";
private static final String UNKNOWN_EXTENSION_MIME_TYPE = "text/plain";
回答by Kezzer
回答by Andreas Dolk
Personally I don't have problems with the if statements. The code is readable, it took just milliseconds to understand what you're doing. It's a private method anyway and if the list of mime types is static then there's no urgent need to move the mapping to a properties file and use a lookup table (map). Map would reduce lines of code, but to understand the code, then you're forced to read the code and the implementation of the mapping - either a static initializer or an external file.
我个人对 if 语句没有问题。代码是可读的,只需几毫秒就可以理解你在做什么。无论如何,它是一个私有方法,如果 mime 类型列表是静态的,那么没有迫切需要将映射移动到属性文件并使用查找表(映射)。Map 会减少代码行数,但要理解代码,您必须阅读代码和映射的实现——静态初始化程序或外部文件。
You couldchange the code a bit and use an enum:
您可以稍微更改代码并使用枚举:
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");
}
The getFileNameExtension(String fileName)method will just return the fitting enum value for the fileName, FileExtension.NONEif fileName is empty (or null?) and FileExtension.DEFAULTif the file extension is not mapped to a mime type.
如果 fileName 为空(或 null?)并且文件扩展名未映射到 mime 类型getFileNameExtension(String fileName),FileExtension.NONE则该方法将只返回适合 fileName 的枚举值FileExtension.DEFAULT。
回答by dfa
what about using a MIME detection libraryinstead?
改用MIME 检测库怎么样?
- mime-util
- mime4j
- JMimeMagic library - Free. Uses file extension and magic headers to determine MIME type.
- mime-util - Free. Uses file extension and magic headers to determine MIME type.
- DROID (Digital Record Object Identification) - Free. Uses batch automation to detect MIME types.
- Aperture Framework - Free. A framework for crawling external sources to identify MIME types.
- mime-util
- mime4j
- JMimeMagic 库 - 免费。使用文件扩展名和魔术头来确定 MIME 类型。
- mime-util - 免费。使用文件扩展名和魔术头来确定 MIME 类型。
- DROID(数字记录对象识别) - 免费。使用批处理自动化来检测 MIME 类型。
- Aperture 框架 - 免费。用于抓取外部资源以识别 MIME 类型的框架。
(feel free to add more, there so many libraries..)
(随意添加更多,有这么多图书馆..)
回答by Pokot0
I consider your approach to be the best overall. This comes after having tested with a number of different approaches myself.
我认为你的方法是最好的整体。这是在我自己使用多种不同方法进行测试之后得出的。
I see a number of huge benefits in your current approach, namely:
我在您当前的方法中看到了许多巨大的好处,即:
- Easily readable and understandableby anyone (in my experience, medium-level programmers often underestimate this and usually prefer going with fancy-patterns which, in the end are not readable at all for the vast majority of programmers who do not know that specific pattern)
- All the information is in one single place. As Andreas_D pointed out, hunting around files or classes is not a good option for someone that needs to fix a bug while you are on holiday!
- Easily maintainable: I could "F3" (if you are Eclipse-ing) on the method and add a new content type in seconds without any worries of introducing bugs!
- 任何人都易于阅读和理解(根据我的经验,中级程序员经常低估这一点,并且通常更喜欢使用花哨的模式,而对于大多数不了解特定模式的程序员来说,最终根本无法阅读)
- 所有信息都集中在一个地方。正如 Andreas_D 指出的那样,对于需要在假期中修复错误的人来说,寻找文件或类并不是一个好的选择!
- 易于维护:我可以在该方法上按“F3”(如果您正在使用 Eclipse)并在几秒钟内添加新的内容类型,而无需担心引入错误!
I can suggest a few things anyway:
无论如何,我可以提出一些建议:
- This method is very general purpose: Why should it be private?! This is a public methodof some utility/helper class! Moreover it should be a static method!! You don't need anything from the Object itself to perform your job!
- You could use indentingto make things prettier and compact. I know that indenting is some kind of religion for the most of us, but I think it should not be a strict rule; it should be properly used to make our code more readable and compact. If this would be a config file you would probably have something like:
- 这个方法很通用:为什么要私有?!这是一些实用程序/助手类的 公共方法!而且它应该是一个静态方法!!您不需要对象本身的任何东西来执行您的工作!
- 您可以使用缩进使事情更漂亮和紧凑。我知道缩进对我们大多数人来说是一种信仰,但我认为这不应该是一个严格的规则;应该正确使用它来使我们的代码更具可读性和紧凑性。如果这将是一个配置文件,您可能会有类似的内容:
pdf=application/pdf doc=application/msword
pdf=application/pdf doc=application/msword
You could have a very similar result with:
您可能会得到非常相似的结果:
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";
}
This is also what a lot of the Map based implementations look like.
这也是许多基于 Map 的实现的样子。
回答by nxhoaf
Command pattern is the way to go. Here is one example using java 8:
命令模式是要走的路。下面是一个使用 java 8 的例子:
1. Define the interface:
1.定义接口:
public interface ExtensionHandler {
boolean isMatched(String fileName);
String handle(String fileName);
}
2. Implement the interface with each of the extension:
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";
}
}
and
和
public class TxtHandler implements ExtensionHandler {
@Override public boolean isMatched(String fileName) {
return fileName.endsWith(".txt");
}
@Override public String handle(String fileName) {
return "txt/plain";
}
}
and so on .....
等等 .....
3. Define the Client:
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. And this is the sample result:
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"
}
回答by Zed
There is no way to evade that in general. In your case - if there is a set of allowed extensions - you could create an Enum, convert the extension to the Enum type via valueOf(), and then you can switch over your enum.
一般来说,没有办法回避这一点。在您的情况下 - 如果有一组允许的扩展名 - 您可以创建一个 Enum,通过 valueOf() 将扩展名转换为 Enum 类型,然后您可以切换您的枚举。
回答by BalusC
Easiest and shortest way for this particular problem would be using the builtin Java SE or EE methods.
解决这个特定问题的最简单和最短的方法是使用内置的 Java SE 或 EE 方法。
Either in "plain vanilla" client application (which derives this information from the underlying platform):
在“普通”客户端应用程序(从底层平台获取此信息)中:
String mimeType = URLConnection.guessContentTypeFromName(filename);
Or in a JSP/Servlet web application (which derives this information from the web.xmlfiles):
或者在 JSP/Servlet Web 应用程序中(从web.xml文件中获取此信息):
String mimeType = getServletContext().getMimeType(filename);
回答by Jesper
I would do this by putting the associations in a map, and then using the map for lookup:
我会通过将关联放在地图中,然后使用地图进行查找来做到这一点:
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));
}
Note that using the switchstatements on strings is one of the proposed new features for the next version of Java; see this pagefor more details and an example of how that would look in Java 7:
请注意,switch在字符串上使用语句是下一版本 Java 建议的新功能之一;有关更多详细信息以及在 Java 7 中的外观示例,请参阅此页面:
switch (fileName.substring(fileName.length() - 4)) {
case ".pdf": return "application/pdf";
case ".doc": return "application/msword";
// ...
default: return null;
(edit: My solution assumes the file extension is always 3 letters; you'd have to change it slightly if it can be longer or shorter).
(编辑:我的解决方案假设文件扩展名始终为 3 个字母;如果它可以更长或更短,您必须稍微更改它)。
回答by aberrant80
Create an enum called MimeType with 2 String variables: extension and type. Create an appropriate constructor and pass in the ".xxx" and the "application/xxx" values. Create a method to do the lookup. You can use enums in switch.
创建一个名为 MimeType 的枚举,其中包含 2 个字符串变量:扩展名和类型。创建适当的构造函数并传入“.xxx”和“application/xxx”值。创建一个方法来进行查找。您可以在 switch 中使用枚举。

