Избегание нескольких операторов If в 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
.
Ответы
Ответ 1
Вы можете использовать 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_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";
Ответ 2
С помощью HashMap возможно?
Таким образом, вы можете сделать myMap.get(mystr);
Ответ 3
Лично у меня нет проблем с операторами if. Код читаем, потребовалось всего миллисекунды, чтобы понять, что вы делаете. Это частный метод в любом случае, и если список типов mime является статическим, то нет необходимости переместить сопоставление в файл свойств и использовать таблицу поиска (карту). Карта уменьшит количество строк кода, но чтобы понять код, вы вынуждены читать код и реализацию сопоставления - либо статический инициализатор, либо внешний файл.
Вы можете немного изменить код и использовать перечисление:
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
, если расширение файла не сопоставлено типу mime.
Ответ 4
как использовать библиотеку обнаружения MIME?
- mime-util
- mime4j
- Библиотека JMimeMagic - бесплатно. Использует расширение файла и магические заголовки для определения типа MIME.
- mime-util - бесплатно. Использует расширение файла и магические заголовки для определения типа MIME.
- DROID (идентификация объекта цифровой записи) - бесплатно. Использует автоматизацию пакетной обработки для обнаружения типов MIME.
- Aperture Framework - бесплатно. Структура для обхода внешних источников для идентификации типов MIME.
(не стесняйтесь добавлять больше, там так много библиотек..)
Ответ 5
Я считаю ваш подход лучшим в целом. Это происходит после того, как я проверил несколько разных подходов.
В вашем текущем подходе я вижу ряд огромных преимуществ, а именно:
- Легко читаемый и понятный кто-либо (по моему опыту, программисты среднего уровня часто недооценивают это и обычно предпочитают ходить с мозаичными шаблонами, которые в конце концов не читаются вообще для подавляющего большинства программистов, которые не знают этого конкретного шаблона)
- Вся информация находится в одном месте. Как указывал Andreas_D, охота вокруг файлов или классов не является хорошим вариантом для тех, кому нужно исправить ошибку, пока вы в отпуске!
- Легко поддерживаемый: я мог бы "F3" (если вы Eclipse-ing) в методе и добавлять новый тип контента за считанные секунды, не опасаясь вводить ошибки!
Я могу предложить несколько вещей в любом случае:
- Этот метод является очень общей целью:
Почему это должно быть частным?! Это
общедоступный метод некоторого класса утилиты/помощника!
Кроме того, это должен быть статический метод ! Вам ничего не нужно
из самого объекта для выполнения
ваша работа!
- Вы можете использовать отступы, чтобы сделать
вещи красивее и компактны. я знаю
этот отступ является своего рода
религия для большинства из нас, но я
думайте, что это не должно быть строгое правило;
его следует правильно использовать для
наш код более доступен для чтения и компактный.
Если это будет файл конфигурации, вы
вероятно, будет иметь что-то вроде:
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";
}
Это то, на что похоже много реализаций на основе карты.
Ответ 6
Нет никакого способа избежать этого вообще. В вашем случае - если есть набор разрешенных расширений - вы можете создать Enum, преобразовать расширение в тип Enum с помощью valueOf(), а затем вы можете переключить свое перечисление.
Ответ 7
Я бы сделал это, поместив ассоциации в карту, а затем используя карту для поиска:
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; см. эту страницу для получения более подробной информации и пример того, как это будет выглядеть в Java 7:
switch (fileName.substring(fileName.length() - 4)) {
case ".pdf": return "application/pdf";
case ".doc": return "application/msword";
// ...
default: return null;
(edit: Мое решение предполагает, что расширение файла всегда 3 буквы, вам придется немного изменить его, если он может быть длиннее или короче).
Ответ 8
Самый простой и короткий путь для этой конкретной проблемы - использовать встроенные методы Java SE или EE.
Либо в клиентском приложении "plain vanilla" (которое выводит эту информацию с базовой платформы):
String mimeType = URLConnection.guessContentTypeFromName(filename);
Или в веб-приложении JSP/Servlet (которое выводит эту информацию из файлов web.xml
):
String mimeType = getServletContext().getMimeType(filename);
Ответ 9
Вы всегда можете использовать класс Groovy здесь, так как он позволяет использовать коммутатор для строк:)
Ответ 10
Как насчет сопоставления расширений с типами 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
Создайте перечисление с именем MimeType с 2 строковыми переменными: расширение и тип. Создайте соответствующий конструктор и передайте значения ".xxx" и "application/xxx". Создайте метод для поиска. Вы можете использовать перечисления в коммутаторе.
Ответ 12
Просто упомянем: прямой эквивалент вашего кода не будет использовать карту для прямого поиска (поскольку для этого требуется, чтобы каждое расширение имело ровно 3 символа), но цикл for:
...
Map<String, String> extmap = GetExtensionMap();
for (Map.Entry<String,String> entry: extmap.entrySet())
if (fileName.endsWith(entry.getKey))
return entry.getValue();
...
Это решение работает с расширениями любой длины, но менее реалистично, чем поиск хэшей, конечно (и немного менее эффективный, чем исходное решение).
Решение алгоритмического дизайна-парня
Более эффективным способом было бы реализовать древовидную структуру, начиная с последнего символа расширения и сохраняя соответствующие типы MIME в соответствующих узлах.
Затем вы можете спуститься по дереву, начиная с последнего символа имени файла. Но это, вероятно, перебор...
Ответ 13
Командный шаблон - путь. Вот один пример использования 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"
}