Присущая коллекциям сложность в Java
Во время мозгового штурма, связанного с написанием моей книги Программирование на Clojure, я обсуждал с опытным учителем Java о коллекциях данных, и он сказал мне, что лучшие в мире преподаватели Java неизменно соглашаются с тем, что поведение коллекций сбивает с толку изучающих Java. в Яве:
– Какие объекты являются коллекциями?
– изменяются ли коллекции методами или нет?
– мы передаем объекты или ссылки от метода к методу?
– когда мы передаем ссылку к методу, мы делаем копию объекта или нет?
Среди опытных преподавателей Java общее мнение состоит в том, что для того, чтобы правильно объяснить, как работают коллекции в Java, им нужно потратить время на объяснение того, как работают стек и куча в Java, как объекты могут иметь ссылки на другие объекты и как это влияет на мусор. коллектор и тд…
Путаница с Java
Позвольте мне проиллюстрировать, насколько запутанны коллекции для изучающих Java, с помощью короткого фрагмента кода:
import java.util.*; public class Main { public static void main(String[] args) { ArrayList myNumbers = new ArrayList<Integer>(Arrays.asList(1,2,3)); ArrayList yourNumbers = myNumbers; yourNumbers.add(4); ArrayList theirNumbers = new ArrayList<Integer>(Arrays.asList(1,2,3)); add5(theirNumbers);
System.out.println("myNumbers: " + myNumbers); System.out.println("yourNumbers: " + yourNumbers); System.out.println("theirNumbers: " + theirNumbers); }
public static void add5(ArrayList a) { a.add(5); } }
ArrayList
объекты изменяемы, поэтому yourNumbers.add(4)
изменяет содержимое yourNumbers
. А как насчет содержания myNumbers
? Он модифицирован или нет? Ведет ли он себя так же, когда мы вызываем метод add в другом методе (например, add5
в нашем примере)?
Когда изучающий Java задает себе эти вопросы, он приходит в замешательство, и, как я упоминал ранее, согласованная стратегия среди преподавателей Java для объяснения поведения коллекций данных состоит в том, чтобы говорить о стеке, куче и сборщике мусора.
(Я не собираюсь рассказывать вам, что выводит приведенный выше фрагмент кода. Цель моей статьи — проиллюстрировать путаницу, возникающую в сознании изучающих Java, и этой путаницы удалось избежать в Clojure.)
Простота чисел
Давайте напишем аналогичный фрагмент кода Java, который имеет дело со значениями, а не с коллекциями:
public class Main { public static void main(String[] args) { int myNumber = 42; int yourNumber = myNumber; yourNumber = yourNumber + 10; int theirNumber = 42; add5(theirNumber);
System.out.println("myNumber: " + myNumber); System.out.println("yourNumber: " + yourNumber); System.out.println("theirNumber: " + theirNumber); }
public static void add5(int a) { int b = a + 5; } }
Когда мы имеем дело с числами, код очень легко понять: каждому, кто изучает Java, ясно, что yourNumber += 10
изменяет yourNumber
, но не myNumber
. Точно так же метод add5
не изменяет theirNumber
.
Причина в том, что числа являются значениями и поэтому никогда не меняются.
Простота Clojure
Clojure — это динамический функциональный диалект LISP, работающий на платформе Java (как и Scala). Clojure поддерживает неизменность и неизменяемые структуры данных.
Опытные преподаватели Clojure сходятся во мнении, что для правильного объяснения того, как работают коллекции в Clojure, единственное, чему они должны научить, это тому, что коллекции данных являются значениями.
В это может быть трудно поверить, но это единственное, что должен понять изучающий Clojure: коллекции данных — это значения. Большая разница между объектами и значениями заключается в том, что значения никогда не меняются. Они неизменны. В Clojure коллекции данных никогда не меняются.
Неизменяемость коллекций в Clojure упрощает понимание кода. Трудность, которую необходимо преодолеть изучающим Clojure, заключается в необычном синтаксисе и странном использовании скобок в стиле LISP. (Помощь Java-разработчикам в изучении синтаксиса Clojure — одна из главных целей моей книги Начните программировать с помощью Clojure.)
Давайте взглянем на похожий фрагмент кода Clojure:
(defn add5 [a] (conj a 5))
(def myNumbers [1 2 3]) (def yourNumbers myNumbers) (conj yourNumbers 4) (def theirNumbers [1 2 3]) (add5 theirNumbers)
(println "myNumbers: " myNumbers) (println "yourNumbers: " yourNumbers) (println "theirNumbers: " theirNumbers)
Как только ученик Clojure привыкнет к синтаксису Clojure, у него не возникнет вопросов о содержании myNumbers
, yourNumbers
и theirNumbers
после выполнения кода.
Их содержание: [1 2 3]
. Причина проста: в Clojure коллекции данных — это значения, точно такие же, как числа. Они никогда не меняются!
Если вам интересно узнать, что такого особенного в Clojure, я приглашаю вас начать читать мою книгу Начните программирование с Clojure, основная цель которой — предоставить Java-разработчикам приятный опыт изучения Clojure.