2013-04-03 2 views
4

Что я хочу сделать, это загрузить пары ключей/значений из файла (excel file using Apache poi) в статическую карту, которая будет использоваться в качестве таблицы поиска. После загрузки таблица не изменится.как передать параметр в статический блок инициализации

public final class LookupTable 
{ 
    private final static Map<String, String> map; 
    static { 
    map = new HashMap<String, String>(); 
    // should do initialization here 
    // InputStream is = new FileInputStream(new File("pathToFile")); 
    // not sure how to pass pathToFile without hardcoding it? 
    } 

    private LookupTable() { 
    } 

    public static void loadTable(InputStream is) { 
    // read table from file 
    // load it into map 
    map.put("regex", "value"); 
    } 

    public static String getValue(String key) { 
    return map.get(key); 
    } 
} 

В идеале я хочу, чтобы загрузить карту внутри блока статической инициализации, но как бы я передать поток в без жесткого кодирования это? Проблема, которую я вижу с помощью статического метода loadTable, может не вызываться перед вызовом других статических методов.

// LookupTable.loadTable(stream); 
LookupTable.getValue("regex"); // null since map was never populated. 

Есть ли лучший подход к этому вопросу?

+0

Принял ответ dasblinkenlight, отвечая на исходный вопрос. Подумав об этом, я, вероятно, перепроектирую и отвечу toto2. – cvue

ответ

1

Вы не можете передавать информацию в блоки статической инициализации - они должны работать изолированно. Поскольку поток, который вы планируете пройти, должен быть известен до начала выполнения программы, предположительно ваш LookupTable должен также найти его. Например, это может быть какая-то утилита настройки, которая обеспечивает поток для вас. Тогда вы можете написать инициализатору так:

static { 
    InputStream exelStream = MyConfigUtil.getExcelStreamForLookup(); 
    loadTable(exelStream); 
} 

Предположительно, есть класс в системе, которые могли бы получить ваш поток Excel из источника, который, как известно, к нему. Источник не нуждается в жестком кодировании: он может считывать местоположение из файла конфигурации или получать данные из предопределенной сетевой папки на вашем сервере. Во всех случаях процесс получения потока Excel должен «снижаться» где-то в том смысле, что что-то в вашей системе должно быть в состоянии найти его без дополнительных параметров.

2

Да, есть лучший подход, использовать шаблон проектирования Factory инициализацию объекта, прежде чем вы должны использовать:

http://www.oodesign.com/factory-pattern.html

0

Это, вероятно, случай для использования отложенной загрузки карты.

Но перед тем, как позвонить getValue(), вам необходимо установить inputFileName. Это будет сделано в вашем коде инициализации для приложений. (Или у вас может быть статический метод для его установки.)

Это указывает на преимущество ленивой загрузки. Вам не обязательно иметь имя файла, пока вы не вызовете getValue() в первый раз. При статической инициализации, вы должны получить имя файла, хранящееся где-то за пределами класса, поэтому он может быть использован для загрузки данных при загрузке класса (но после того, как статические поля инициализированы.

public static String inputFileName = null; 

public static String getValue(String key) { 
    if (map == null) { 
     map = = new HashMap<String, String>(); 
     // open the file using 'inputFileName' 
     loadTable(InputStream is); 
    } 
    return map.get(key); 
    } 

Если код многопоточность, дайте мне знать, и я буду комментировать по вопросам синхронизации

Alternate

Вы можете также использовать Spring впрыснуть карту и построить его в другом классе -.. MapBuilder например

+0

Как «getValue» знает «InputStream»? –

+0

@Heuster Добавлен способ. –

2

Все, что вы используете, должно быть доступно при запуске. Насколько я знаю, ваши варианты:

  1. Жесткий код пути. Это плохо по понятным причинам.
  2. Статическая переменная или статический метод. Это представляет собой проблему с курицей и яйцом; в конечном итоге он становится жестко закодированным, но по крайней мере вы можете выполнить поиск с помощью метода static.
  3. Используйте переменную Java или среду. Итак, вы бы использовали что-то System.getProperty("filename", "/default/filename"). Лучше, потому что он по крайней мере настраивается с использованием среды или параметров -D при запуске JVM.
  4. Использование методов ClassLoadergetResource*. Это, вероятно, правильный ответ. В частности, вы, вероятно, захотите использовать метод getResourceAsStream() в контексте текущего потока ClassLoaderThread.currentThread().getContextClassLoader(). (Итак, Thread.currentThread().getContextClassLoader().getResourceAsStream("filename") в общей сложности.) ClassLoader найдет для вас ваш ресурс (если вы положите его куда-нибудь в своем CLASSPATH).
0

Попробуйте использовать System.getProperty() и передайте параметр с -D в командной строке.

static String prop; 

static { 
    prop = System.getProperty("java.home"); 
} 

public static void main(String... args) { 

    System.out.println(prop); 
} 
0

Это непосредственно не отвечая на ваш вопрос, но я не понимаю, почему map должен быть статическим. Вы можете изменить map на нестатический и изменить конструктор на public LookupTable(File file) {...fill map...}. Тогда у вас может быть много экземпляров этого класса, если у вас есть разные файлы excel; теперь это может быть не так, но это будет «будущий» код.

0

Я предлагаю singleton enum approach, если это подходит вашему делу.

public enum LookupTable { 

    INSTANCE(FileManager.getFileName()); 

    LookupTable(String fileName){ 
     props = new HashMap<String,String>(); 
     //Read from excel and fill the hashmap 
    } 

    private final Map<String, String> props; 

    public String getMapValue(String key){ 
     return props.get(key); 
    } 
} 

который может быть вызван

LookupTable.INSTANCE.getMapValue("mykey"); 

Это будет вызывать эти методы, чтобы

  • Получить имя файла из класса FileManager, который параметризованных от ваших потребностей
  • Вызовите конструктор (частный) и свойства загрузки из файла excel
  • getMapValue для ключа и возврата

последующего LookupTable.INSTANCE.getMapValue вызова («mysecondkey») будет вызывать только getMapValue как INSTANCE инициализируется заранее.

Смежные вопросы