Вы должны изменить код вашей серверной части, как указано ниже
public class CorsResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
}
}
я добрался, много хороших ответов на этот вопрос - благодарит людей - таким образом, я решил запустить некоторые тесты и фигуру, какой метод является на самом деле самым быстрым. Эти пять методов, которые я протестировал, являются ими:
Здесь, - то, что я сделал...
я представлю результаты сначала и код ниже для тех, кому интересно.
метод ContainsKey был, как ожидалось, самым медленным, таким образом, я дам скорость каждого метода по сравнению со скоростью того метода.
, казалось бы, что только метод MutableInt и метод Находки значительно быстрее в том единственном, которое они дают повышению производительности больше чем 10%. Однако, если поточная обработка является проблемой, AtomicLong мог бы быть более привлекательным, чем другие (я не действительно уверен). Я также выполнил TestForNull с final
переменные, но различие было незначительно.
Примечание, что я не представил использование памяти в различных сценариях. Я был бы рад получить известие от кого-либо, у кого есть хорошее понимание того, как методы MutableInt и Находки, вероятно, влияли бы на использование памяти.
Лично, я нахожу метод MutableInt самым привлекательным, так как он не требует загрузки никаких сторонних классов. Таким образом, если я не обнаруживаю проблемы с ним, это - путь, которым я, скорее всего, пойду.
Вот решающий код из каждого метода.
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
int count = freq.containsKey(word) ? freq.get(word) : 0;
freq.put(word, count + 1);
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
Integer count = freq.get(word);
if (count == null) {
freq.put(word, 1);
}
else {
freq.put(word, count + 1);
}
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
...
final ConcurrentMap<String, AtomicLong> map =
new ConcurrentHashMap<String, AtomicLong>();
...
map.putIfAbsent(word, new AtomicLong(0));
map.get(word).incrementAndGet();
import gnu.trove.TObjectIntHashMap;
...
TObjectIntHashMap<String> freq = new TObjectIntHashMap<String>();
...
freq.adjustOrPutValue(word, 1, 1);
import java.util.HashMap;
import java.util.Map;
...
class MutableInt {
int value = 1; // note that we start at 1 since we're counting
public void increment () { ++value; }
public int get () { return value; }
}
...
Map<String, MutableInt> freq = new HashMap<String, MutableInt>();
...
MutableInt count = freq.get(word);
if (count == null) {
freq.put(word, new MutableInt());
}
else {
count.increment();
}
Я использовал бы Наборы Apache Ленивая Карта (для инициализации значений к 0) и использовал бы MutableIntegers от Apache Lang как значения в той карте.
Самая большая стоимость должна искать карту дважды в Вашем методе. В моем необходимо сделать это только однажды. Просто получите значение (оно будет инициализировано, если отсутствующий), и увеличивают его.
@Vilmantas Baranauskas: Относительно этого ответа я прокомментировал бы, были ли у меня точки представителя, но я не делаю. Я хотел отметить что Встречный класс, определенный, там не ориентировано на многопотоковое исполнение, поскольку не достаточно просто синхронизировать inc (), не синхронизируя значение (). Другие потоки, называя значение (), как гарантируют, не будут видеть значение, если происхождение - перед отношениями не было установлено с обновлением.
Различные примитивные обертки, например, Integer
неизменны, таким образом, существует действительно не более краткий способ сделать то, что Вы спрашиваете , если Вы не можете сделать это с чем-то как AtomicLong. Я могу дать этому движение через минуту и обновление. BTW, Хеш-таблица часть эти Платформа Наборов .
Я думаю, что Вашим решением был бы стандартный путь, но - поскольку Вы отметили себя - это - вероятно, не самый быстрый возможный путь.
можно посмотреть Находка GNU . Это - библиотека, которая содержит все виды быстрых примитивных Наборов. Ваш пример использовал бы TObjectIntHashMap, который имеет метод adjustOrPutValue, который делает точно, что Вы хотите.
Вместо того, чтобы назвать containsKey () это быстрее только для вызова map.get и проверки, если возвращенное значение является пустым или нет.
Integer count = map.get(word);
if(count == null){
count = 0;
}
map.put(word, count + 1);
Вы уверены, что это - узкое место? Вы сделали какой-либо анализ производительности?
Попытка с помощью профилировщика NetBeans (его свободное и встроенный в NB 6.1) для рассмотрения горячих точек.
Наконец, обновление JVM (говорят от 1.5-> 1.6) часто является дешевым усилителем производительности. Даже обновление в номере сборки может обеспечить хорошие повышения производительности. Если Вы работаете на Windows, и это - приложение класса сервера, используйте - сервер на командной строке для использования JVM Горячей точки Сервера. На машинах Linux и Соляриса это автоматически обнаруживается.
Вращение памяти может быть проблемой здесь, начиная с каждой упаковки интервала, больше, чем, или равняться 128 причинам объектному выделению (см. Integer.valueOf (интервал)). Хотя сборщик "мусора" очень эффективно имеет дело с недолгими объектами, производительность пострадает до некоторой степени.
, Если Вы знаете, что количество инкрементов составило завещание в основном, превосходят численностью количество ключей (=words в этом случае), рассматривают использование международного держателя вместо этого. Phax уже представил код для этого. Здесь это снова с двумя изменениями (класс держателя, сделанный набором статического и начального значения к 1):
static class MutableInt {
int value = 1;
void inc() { ++value; }
int get() { return value; }
}
...
Map<String,MutableInt> map = new HashMap<String,MutableInt>();
MutableInt value = map.get(key);
if (value == null) {
value = new MutableInt();
map.put(key, value);
} else {
value.inc();
}
при необходимости в экстремальной производительности ищите Реализацию Map, которая непосредственно адаптируется к примитивным типам значения. jrudolph упомянул Находка GNU .
Между прочим, хороший критерий поиска для этого предмета является "гистограммой".
Иначе создал бы изменяемое целое число:
class MutableInt {
int value = 0;
public void inc () { ++value; }
public int get () { return value; }
}
...
Map<String,MutableInt> map = new HashMap<String,MutableInt> ();
MutableInt value = map.get (key);
if (value == null) {
value = new MutableInt ();
map.put (key, value);
} else {
value.inc ();
}
, конечно, это подразумевает создание дополнительного объекта, но издержки по сравнению с созданием Целого числа (даже с Integer.valueOf) не должны быть так.
Необходимо знать о том, что исходная попытка
int count = map.containsKey(word) ? map.get(word) : 0;
содержит две потенциально дорогих операции на карте, а именно, containsKey
и get
. Первый выполняет операцию, потенциально симпатичную подобный последнему, таким образом, Вы делаете ту же работу дважды !
при рассмотрении API для Карты, get
операции обычно возвращаются null
, когда карта не содержит требуемый элемент.
Примечание, что это сделает решение как [1 132]
map.put( key, map.get(key) + 1 );
опасным, так как оно могло бы уступить NullPointerException
с. Необходимо проверить на null
сначала.
Также примечание , и это очень важно, тот HashMap
, s может содержать nulls
по определению. Так не каждый возвращенный null
говорит, что "нет такого элемента". В этом отношении, containsKey
ведет себя по-другому от [1 113] в фактическом сообщении Вам ли существует такой элемент. Обратитесь к API для деталей.
Для Вашего случая, однако, Вы не могли бы хотеть различать сохраненный null
и "noSuchElement". Если Вы не хотите разрешать null
с, Вы могли бы предпочесть Hashtable
. Используя библиотеку-оболочку, как был уже предложен в других ответах, могло бы быть лучшее решение ручной обработки, в зависимости от сложности Вашего приложения.
Для завершения ответа (и я забыл вставлять это сначала благодаря функции редактирования!), лучший способ сделать его исходно, к [1 117] в final
переменная, проверьте на [1 119], и put
это въезжает задним ходом с 1
. Переменная должна быть final
, потому что это неизменно так или иначе. Компилятору, возможно, не понадобилась бы эта подсказка, но его более ясное тот путь.
final HashMap map = generateRandomHashMap(); final Object key = fetchSomeKey(); final Integer i = map.get(key); if (i != null) { map.put(i + 1); } else { // do something }
, Если Вы не хотите полагаться на автоупаковку, необходимо сказать что-то как [1 123] вместо этого.
Это всегда - хорошая идея посмотреть Google Collections Library для такого рода вещи. В этом случае Мультимножество добьется цели:
Multiset bag = Multisets.newHashMultiset();
String word = "foo";
bag.add(word);
bag.add(word);
System.out.println(bag.count(word)); // Prints 2
существуют подобные Карте методы для итерации по ключам/записям, и т.д. Внутренне реализация в настоящее время использует HashMap<E, AtomicInteger>
, таким образом, Вы не понесете расходы упаковки.
@Hank Gay
Как продолжение моего собственного (довольно бесполезного) комментария: Находка похожа на способ пойти. Если по любой причине Вы хотели придерживаться стандартного JDK, ConcurrentMap и , AtomicLong может сделать код крошечным , укусил более хороший, хотя YMMV.
final ConcurrentMap<String, AtomicLong> map = new ConcurrentHashMap<String, AtomicLong>();
map.putIfAbsent("foo", new AtomicLong(0));
map.get("foo").incrementAndGet();
уедет 1
как значение в карте для foo
. Реалистично, увеличенное дружелюбие к поточной обработке - все, что этот подход должен рекомендовать его.
Существует несколько подходов:
Использование Сумка alorithm как наборы содержится в Google Collections.
Создают изменяемый контейнер, который можно использовать в Карте:
class My{
String word;
int count;
}
И помещенное использование ("слово", новое Мой ("Word")); Тогда можно проверить, существует ли это и инкремент при добавлении.
Стараются не прокручивать Ваше собственное решение с помощью списков, потому что, если Вы получаете innerloop поиск и сортировка, Ваша производительность будет вонять. Первое решение HashMap на самом деле довольно быстро, но надлежащее как найденный в Google Collections, вероятно, лучше.
слова подсчета с помощью Google Collections, выглядит примерно так:
HashMultiset s = new HashMultiset();
s.add("word");
s.add("word");
System.out.println(""+s.count("word") );
Используя HashMultiset довольно изящно, потому что алгоритм сумки, в чем Вы нуждаетесь при подсчете слов.
Я предлагаю использовать Карту Java 8:: вычислите (). Это рассматривает случай, когда ключ не существует, также.
Map.compute(num, (k, v) -> (v == null) ? 1 : v + 1);
Функциональная библиотека Java TreeMap
структура данных имеет метод обновления
в последней заголовке ствола:
public TreeMap<K, V> update(final K k, final F<V, V> f)
Пример использования:
import static fj.data.TreeMap.empty;
import static fj.function.Integers.add;
import static fj.pre.Ord.stringOrd;
import fj.data.TreeMap;
public class TreeMap_Update
{public static void main(String[] a)
{TreeMap<String, Integer> map = empty(stringOrd);
map = map.set("foo", 1);
map = map.update("foo", add.f(1));
System.out.println(map.get("foo").some());}}
Эта программа печатает «2».