Присущая коллекциям сложность в 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.