Clojure: работа с java.util.HashMap идиоматическим способом Clojure

Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.

Например, ниже - класс ученика, который будет использовать его в нашем коде.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Приведенный ниже код дает вам исключение с нулевым указателем.

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}

Поскольку вы используете Obj_Student, но вы забыли инициализировать его, как в правильном коде, показанном ниже:

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student = new Student();
            obj_Student.setId(12);
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}
26
задан Cœur 3 September 2017 в 15:24
поделиться

4 ответа

Clojure делает java-коллекции последовательными, поэтому вы можете напрямую использовать функции последовательности Clojure в java.util.HashMap .

Но assoc ожидает clojure.lang.Associative , поэтому вам нужно сначала преобразовать java.util.HashMap в следующее:

(assoc (zipmap (.keySet m) (.values m)) "key" "value")

Изменить: более простое решение:

(assoc (into {} m) "key" "value")
33
ответ дан 28 November 2019 в 04:43
поделиться

Совершенно нормально использовать хэш-карту java традиционным способом.
(do (. M put "key" "value") m)
Это не идиоматический код Clojure, плюс я изменяю m вместо создания новой карты.

Вы изменяете структуру данных, которая действительно предназначена для изменения. В хэш-карте Java отсутствует структурное совместное использование , которое позволяет эффективно копировать карты Clojures. Обычно идиоматический способ сделать это - использовать функции java-interop для работы со структурами java типичным способом java или чисто преобразовать их в структуры Clojure и работать с ними функциональным способом Clojure. Если, конечно, это не облегчит жизнь и не приведет к улучшению кода; тогда все ставки отменены.

5
ответ дан 28 November 2019 в 04:43
поделиться

Это код, который я написал с использованием хэш-карт, когда пытался сравнить характеристики памяти версии clojure и версии java (но использованной из clojure)

(import '(java.util Hashtable))
(defn frequencies2 [coll]
    (let [mydict (new Hashtable)]
      (reduce (fn [counts x]
            (let [y (.toLowerCase x)]
              (if (.get mydict y)
            (.put mydict y (+ (.get mydict y) 1))
            (.put mydict y 1)))) coll) mydict))

Это нужно взять некоторую коллекцию и вернуть, как много раз каждая отдельная вещь (скажем, слово в строке) используется повторно.

1
ответ дан 28 November 2019 в 04:43
поделиться

Если вы взаимодействуя с кодом Java, вам, возможно, придется укусить пулю и сделать это способом Java, используя .put . Это не обязательно смертный грех; Clojure предлагает такие функции, как do и . в частности, чтобы вы могли легко работать с кодом Java.

assoc работает только со структурами данных Clojure, потому что было проделано много работы, чтобы сделать создание новых (неизменяемых) их копий с небольшими изменениями очень дешевым. Java HashMaps не предназначены для работы таким же образом. Вам придется клонировать их каждый раз, когда вы вносите изменения, что может быть дорогостоящим.

Если вы действительно хотите выбраться из страны мутаций Java (например, возможно, вы ' храните эти HashMap в течение долгого времени и не хотите, чтобы вызовы Java были повсюду, или вам нужно сериализовать их через print и read , или вы хотите работать с их поточно-ориентированным способом с использованием Clojure STM) вы можете достаточно легко преобразовать между Java HashMaps и Clojure hash-map, потому что структуры данных Clojure реализуют правильные интерфейсы Java, поэтому они могут общаться друг с другом.

user> (java.util.HashMap. {:foo :bar})
#<HashMap {:foo=:bar}>

user> (into {} (java.util.HashMap. {:foo :bar}))
{:foo :bar}

Если вам нужен do -подобная вещь, которая возвращает объект, над которым вы работаете, после того как вы закончили работу над ним, вы можете использовать doto . Фактически, Java HashMap используется в качестве примера в официальной документации для этой функции, что является еще одним признаком того, что это еще не конец света, если вы используете объекты Java (разумно).

clojure.core/doto
([x & forms])
Macro
  Evaluates x then calls all of the methods and functions with the
  value of x supplied at the front of the given arguments.  The forms
  are evaluated in order.  Returns x.

  (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))

Некоторые возможные стратегии:

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

  2. Если ваши объекты будут существовать какое-то время или с ними нужно хорошо играть другой код Clojure, постарайтесь как можно скорее поместить их в структуры данных Clojure и в последнюю секунду вернуть их в Java HashMaps (при отправке их обратно в Java).

24
ответ дан 28 November 2019 в 04:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: