Вы достигли нового уровня

Уровень 29

1. NamingConventions, CodeConventions

- Привет, Амиго! Сегодня я расскажу тебе о стилях кода и важности стилей кода.

Начну с самого главного. Код в Java должен быть легко читаем. Общий подход к коду такой – код пишется один раз, а читается сто.

Например, ты и еще 10 программистов занимаетесь написанием программы. Программа пишется три года, с промежуточными релизами каждые три месяца.

- Так долго?

- Это Java, детка! Как насчет Enterprise-системы, которая работает на десятке серверов и которую пишут более 6 лет около 100 человек? Бывает и такое.

- Ничего себе.

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

В других языках программирования люди часто работают маленькими командами над маленькими задачами, поэтому у них может быть другой главный критерий, например – «Это работает? Вот и отлично»

За пару лет в написанный тобой код успеют по нескольку раз внести изменения все члены команды. И каждый раз им придется разбираться, а как же работает этот код?

И если код просто отлично делал свое дело, но был непонятен, то поменять его трудно. Его выкинут и напишут по-своему. Поэтому, пиши код, понятный другим. Если можешь улучшить код – улучши его. Если его можно улучшить, значит, его нужно улучшить!

Если ты написал код за 15 минут и два часа улучшаешь его – ты все делаешь правильно. Сколько времени ты экономишь команде?

«2 часа на разбор твоего кода» x «100 раз, когда люди будут в нем разбираться» = 200 часов.

Эти цифры взяты с потолка, но я хочу, чтобы ты понял проблему и ее масштаб. Твой код создается для чтения другими программистами. Все остальное – вторично.

Код плохо работает? Исправим. Не оптимально? Оптимизируем. Не документирован? Прокомментируем.

Код плохо читаем? Выкинуть его нафиг и написать все заново!

- Не думал, что это такая проблема.

- Java поэтому и один из лидирующих языков программирования, что весь ее код пишется, чтобы читаться другими программистами.

Теперь перейдем к вопросу номер два – «А как писать максимально читаемый код?».

Любому понятно, когда с ним говорят на родном языке, родными знакомыми словами. Так и тут. Код легко читаем, когда программист, читающий его, с легкостью догадывается:

А) Что делает каждый метод

Б) Какой цели служит каждый класс

В) Что именно хранится в каждой переменной.

Все это определяется по названию: имени класса, имени метода, имени переменной. Кроме того, есть еще стиль именования переменных. И стиль кода.

- Я готов слушать.

- В основе программирования лежит… английский язык! Хорошо написанная программа читается, как обычная техническая документация на английском языке.

Начнем с имен.

Имя метода должно кратко описывать, что этот метод делает. Тогда программист может читать программу, как простой текст.

Программа
public String downloadPhoto(String url)
{
 String resultFileName = TempHelper.createTempFileName();

 Downloader downloader = new SingleFileDownloader(new Url(url));
 downloader.setResultFileName(resultFileName)
 downloader.start();
 while(downloader.isDone())
 {
  Thread.sleep(1000);
 }

 if (downloader.hasError())
  return null;

 return resultFileName;
}

Вот как читается такая программа.

Строка 1.

Метод называется «downloadPhoto», похоже, что он загружает файл с фотографией из интернета. Куда загружает? Пока неизвестно. Откуда? В параметрах метода передан url – скорее всего это и есть ссылка для загрузки.

Строка 3.

Объявляется переменная resultFileName, в нее ложится значение, отданное методом TempHelper.createTempFileName();

Имя переменной resultFileName дословно переводится как «имя-файла-результата». Значит это локальный путь к файлу на диске, куда мы будем сохранять наш скачиваемый файл.

Название TempHelper – ничего не говорит. Суффикс Helper говорит, что это разновидность утилитных классов, которые не содержат в себе серьезной бизнес логики, а используются для упрощения часто возникающих рутинных задач.

Имя метода createTempFileName говорит о том, что этот метод создает и возвращает нам имя временного файла (temp-file). Temp file – это временный файл, который создается на время, и обычно удалятся после закрытия программы или раньше.

Строка 5.

Создается объект типа SingleFileDownloader и кладется в переменную downloader.

Название переменной downloader переводится как загрузчик. Этот объект и будет загружать наш файл из интернета.

В переменную downloader кладется объект типа SingleFileDownloader. Из названия можно предположить, что в программе есть несколько видов классов-загрузчиков файлов. Один из них написан для загрузки единственного файла (single file), и скорее всего можно ожидать встретить в коде и загрузчики для группы файлов с названиями вроде: MultiFileDownloader, GroupFileDownloader или DirectoryDownloader

Строка 6.

Объекту downloader устанавливаем в свойство resultFileName значение переменной resultFileName. Т.е. мы говорим загрузчику, куда сохранять скачиваемый им файл. Что и следовало ожидать. Т.е. мы уже практически предсказываем код!

Строка 7.

Вызов метода start. Начало загрузки. Логично. Интересно, как будет происходить загрузка: кусочками, в отдельной нити или сразу до конца. Если сразу, то это может быть долго и иметь последствия.

Строки 8-11.

Ага. Тут мы видим обычный цикл, который ждет завершения загрузки. Объект downloder имеет свойство done («готово») и метод, который его возвращает isDone(). Т.к. метод называется isDone(), а не getDone(), то переменная done имеет тип boolean, ну или Boolean.

Строки 13-14.

Если в процессе скачивания произошла ошибка, то метод downloadPhoto возвращает null. Хорошо, что он обрабатывает состояние ошибки. Плохо, что он просто возвращает null – что за ошибка – не ясно. Лучше бы кинул исключение с информацией об ошибке.

Строка 16.

Возвращаем путь к локальному файлу, который содержит скачанный файл.

- Ничего себе!

- Из текста этой программы абсолютно ясно, что она делает. Можно даже делать предположения, как устроена программа и какие еще классы/методы мы будем встречать.

- Теперь я понял, как важны имена.

- Еще насчет имен. Очень часто можно угадать какие у объекта/класса есть методы. Вот например, если объект – коллекция, то скорее всего у него будут методы size() или count(), чтобы получить количество его элементов. Так же, вероятно, методы add(добавить) или put(вставить). Методы get/getItem, getElement используются для получения элементов у классов-коллекций.

Если переменная называется i, j ,k – скорее всего это счетчик цикла.

Если переменная называется m, n – скорее всего это размер массива/коллекции.

Если переменная называется name то, скорее всего она имеет тип String и содержит чье-то имя.

Если класс называется FileInputStream, то он одновременно является файлом (так и есть) и потоком для чтения – InputStream (так и есть).

Чем больше ты видел кода, тем легче читать чужой код.

Но иногда есть код, который читать очень сложно. На этот случай есть один очень дельный совет:

Совет
Пишите свой код так, как будто поддерживать его будет склонный к насилию психопат, который знает, где вы живете.

- Смешно и не смешно одновременно.

- Теперь немного расскажу о стилях именования переменных.

В Java переменным и методам стараются давать максимально информативные имена. Поэтому такие названия часто состоят из нескольких слов. Есть 4 стиля написания составных имен.

1) Lowercase (нижний регистр) – все слова с маленькой буквы. Пример:

Green house превращается в greenhouse

Hollywood girl превращается в hollywoodgirl

В таком стиле пишутся названия пакетов (package).

2) Uppercase (верхний регистр) – все слова пишутся с большой буквы, разделенные знаком подчеркивания. Примеры:

Max value превращается в MAX_VALUE

Cats count превращается в CATS_COUNT

В таком стиле пишутся названия переменных-констант (final static).

3) CamelCase (верблюжий стиль) – все слова пишутся с маленькими буквами, первая буква каждого слова – большая. Примеры:

Green house превращается в GreenHouse

Hollywood girl превращается в HollywoodGirl

В таком стиле пишутся названия классов и интерфейсов.

4) Lower CamelCase (смешанный стиль) – все слова пишутся маленькими буквами, первая буква каждого слова – большая, первая буква первого слова - маленькая. Примеры:

Get width превращается в getWidth

Get Hollywood girl name превращается в getHollywoodGirlName

В таком стиле пишутся названий переменных и методов.

Т.е. правил не так уж и много.

1) Всё пишется в Lower Camel Case.

2) Имена классов и интерфейсов – всегда с большой буквы.

3) Имена пакетов – всегда маленькими.

4) Константы - всегда большими.

Есть еще пара нюансов, но в целом так и есть.

Теперь насчет методов. Имена методов практически всегда начинаются с глагола! Имя метод count – плохое имя. Лучше назвать getCount(). Метод выполняет какое-то действие над объектом: startDowbload (начать загрузку), interrupt (прервать), sleep (спать), loadPirateMusic(загрузить пиратскую музыку).

Для работы со свойствами/полями объекта, как ты уже знаешь, есть getter’ы и setter’ы. getName/setName, getCount/setCount и т.д.

Единственное исключение делается для типа boolean. Для него getter пишется не через get, а через is: isDone, isEmpty. Так ближе к английскому языку.

- Т.е. знание английского обязательно для умения программировать?

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

- Ага!

- То-то и оно. Основное требование у Java Junior - это отличное знание основ Java – Java Core. Но чем опытнее ты становишься, тем сильнее тебе нужен английский. Чем раньше начнешь его учить – тем лучше.

- У меня еще вопрос. Почему такие разные методы для получения количества элементов?

КлассМетод для получения количества элементов
String метод length()
Array свойство length
ArrayList метод size()
ThreadGroup метод activeCount()

Во-первых, Java была придумана более 20 лет назад, когда требований вроде setCount/getCount еще не было, и в ходу был подход из языка С++ «сделай это как можно короче»

Во-вторых, тут играет роль семантика английского языка. Так уж получилось, что когда говорят про массив, употребляют length, а когда про коллекцию – size.

В русском языке тоже есть такие устоявшиеся выражения:

1) Тарелка на столе стоит, а на полу – лежит.

2) Ботинок на столе лежит, а на полу – стоит.

- Какая интересная лекция.

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

Еще хотел бы коснуться стиля скобок {}. Есть два подхода:

1) Скобка каждый раз ставится на новой строке

2) Открывающая скобка ставится в конце предыдущей строки, закрывающая – на новой. Такой стиль еще называют «египетскими скобками».

Честно говоря – тебе выбирать, как писать. Многие пишут открывающую скобку на той же строке, многие - на новой. Это как спор – с какого конца разбивать яйцо: с тупого или острого.

Единственное, что могу посоветовать – это придерживайся того же стиля, что и в проекте, в котором ты работаешь. Не стоит менять чужой код, как тебе удобнее. Люди несовершенны, это я тебе как доктор Билаабо говорю.

- Спасибо за интересную лекцию, Билаабо. Пойду обдумывать услышанное.

2. Задачи на NamingConventions (исправить что-то, чтобы соответствовало стандарту)

- Привет, Амиго!

Задачи
1. Рефакторинг в соответствии с Naming and Code Convention

Исправить код в соответствии с Naming and Code Convention (Shift+F6 для рефакторинга)
Не оставлять комментариев, проверяется строгое соответствие стандарту

Подсказка: IDEA не умеет правильно переименовывать имена классов, если меняется только регист.
Переименуйте имя класса во вспомогательное имя, а потом в это же в правильном регистре.
2. Рефакторинг в соответствии с Naming and Code Convention 2

Исправить код в соответствии с Naming and Code Convention (Shift+F6 для рефакторинга)
Не оставлять комментариев, проверяется строгое соответствие стандарту

3. Autoboxing (imutables)

- Привет, Амиго!

Сегодня я расскажу про autoboxing. Box – это коробка. Boxing – упаковка. А AutoBoxing – это соответственно – автоматическая упаковка.

Насколько ты помнишь, в Java есть как типы, унаследованные от класса Object, так и примитивные типы. Но, как оказалось, такая удобная вещь как коллекции и generic’и могут работать только с типами, унаследованными от Object.

Тогда было приятно решение сделать не примитивный аналог каждого примитивного типа.

Примитивный типНе-примитивный аналог
byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character
void Void

Но каждый раз преобразовывать эти типы друг в друга оказалось не очень удобно:

 
int x = 3;
Integer y = new Integer(x+1);
int z = y.intValue();

Особенно, если работать сразу с коллекциями:

Пример
int[] numbers = new int[10];
ArrayList<Integer> list = new ArrayList<Integer>();

for (int i=0;i
{
 list.add( new Integer(i));
}

Поэтому разработчики Java придумали автоматическую «упаковку» (boxing) и «распаковку» (unboxing) примитивных типов в их непримитивные аналоги.

Вот как это работает:

Видимый кодЧто происходит на самом деле
int x = 3;
Integer y = x+1;
int x = 3;
Integer y = Integer.valueOf( x+1);
int z = y; int z = y.intValue();
Boolean b = Boolean.FALSE;
boolean a = b;
Boolean b = Boolean. FALSE;
boolean a = b.booleanValue();
Integer x = null;
int y = x;
Integer x = null; int y = x.intValue(); //кинется исключение

Все просто. Ты можешь присваивать типы int и Integer друг-другу, об остальном позаботится компилятор.

- Это очень удобно.

- Ага. Но есть нюансы, о которых я расскажу дальше.

4. Number (Integer Long, Byte)

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

Во-первых, придумали абстрактный класс Number (число), от которого унаследованы типы Byte, Short,Integer, Long, Float, Double. У него есть методы, которые помогают преобразовывать числа к другим числовым типам.

 Методы класса Number
1 int intValue()
2 long longValue()
3 float floatValue()
4 double doubleValue()
5 byte byteValue()
6 short shortValue()

- Действительно, ведь уже не напишешь:

 
Long x = 100000;
Integer y = (Integer) x;

- Ага. Типы то не примитивные. Поэтому используют методы класса Number:

 
Long x = 100000;
Integer y = x.intValue();

Но тут есть еще пара моментов. Т.к. Integer – это не int, то объекты такого типа нельзя сравнивать классическим знаком «==».

Сравнение примитивных типов
int x = 500;
int y = 500;

x == y; //true
Сравнение непримитивных типов:
Integer x = 500;
Integer y = 500;

x == y; //false
x.equals(y); //true

- Точно. Как-то я сразу об этом не подумал.

- Но и это еще не все.

- Господи, что же там еще-то?

- Когда мы присваиваем переменной типа Integer значение типа int, при этом вызывается метод Integer.valueOf:

КодЧто происходит на самом деле
Integer x = 5; Integer x = Integer.valueOf(5);

- Ага. Я это понял еще примером выше.

- Так вот, функция valueOf не всегда создает новый объект типа Integer.

- Т.е. как это не всегда?

- Она кэширует значения от -128 до 127.

КодЧто происходит на самом делеОписание
Integer x = 300;
Integer y = 300;
Integer z = 300;
Integer x = Integer.valueOf(300);
Integer y = Integer.valueOf(300);
Integer z = Integer.valueOf(300);
Все переменные x,y,z содержат ссылки на разные объекты
Integer x = 100;
Integer y = 100;
Integer z = 100;
Integer x = Integer.valueOf(100);
Integer y = Integer.valueOf(100);
Integer z = Integer.valueOf(100);
Все переменные x,y,z содержат ссылки на один и тот же объект.
Integer x = new Integer(10)
Integer y = new Integer(10)
Integer z = 10;
Integer t = 10;
Integer x = new Integer(10)
Integer y = new Integer(10)
Integer z = Integer.valueOf(10);
Integer t = Integer.valueOf(10);
Все переменные z,t содержат ссылки на один и тот же объект.

Т.е. ситуация такая:

1) Если мы пишем new Integer(), то гарантированно создается новый объект.

2) Если мы вызываем Integer.valueOf(), явно или при autoboxing, то этот метод может вернуть для нас как новый объект, так и отдать объект из кэша, если переданное число лежит в диапазоне от -128 до 127.

- Ага. А можно устанавливать/менять приоритет нити после ее запуска? Или тут как с setDaemon – обязательно выставить значение до старта нити?

- Приоритет можно менять и после старта. Как я уже говорила, кардинальных изменений это не влечет.

- А что в этом такого страшного, если метод вернет объект из кэша?

- Да ничего. Просто нужно знать, что иногда, когда этого не ожидаешь, объекты могут быть равны. Там с равенством вообще все сложно. Если мы сравниваем примитивный тип и не примитивный, то они сравниваются как примитивы:

Пример проблемы со сравнением:
int x = 300;
Integer y = 300;
Integer z = 300;


x==y; //true (сравниваются как примитивы по значению)
x==z; //true (сравниваются как примитивы по значению)
y==z; //false (сравниваются по ссылке)
Этот пример еще интереснее. Тут уже в дело вступает кэш
int x = 100;
Integer y = 100;
Integer z = 100;


x==y; //true (сравниваются как примитивы по значению)
x==z; //true (сравниваются как примитивы по значению)
y==z; //true (сравниваются по ссылке, ссылаются на один и тот же объект)
А тут кэш уже не работает
int x = 100;
Integer y = new Integer(100);
Integer z = 100;


x==y; //true (сравниваются как примитивы по значению)
x==z; //true (сравниваются как примитивы по значению)
y==z; //false (сравниваются по ссылке, ссылаются на различные объекты)

- М-да. И как все это запомнить…

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

Еще советую тебе посмотреть на методы класса Integer, у него довольно много хороших и полезных методов. Ты даже одним из них часто пользовался.

- Ага. Помню. Integer.parseInt();

5. Задачи на автобоксинг и числа

- Привет, Амиго!

Задачи
1. И еще раз рефакторинг

1. Исправить код в соответствии с Naming and Code Convention (Shift+F6 для рефакторинга)
2. Просмотрите методы класса ConcurrentMap.
3. В строке "String previousEntry = null;" у concurrentMap вызовите метод,
который вставит пару (randomInt, text) только для ключа, которого нет в concurrentMap.
Метод должен возвращать предыдущее значение либо null для новой пары.
2. Особенности автобоксинга

Исправьте ошибку в методе getValueByIndex.
Читайте доп. статью про особенности автобоксинга.

6. Boolean

- Привет, Амиго!

- Привет, Ким.

- Я тебе расскажу про тип Boolean. Это тоже «обертка» над типом boolean и он прост как доска. Немного упрощенный код класса Boolean:

Код
class Boolean
{
 public static final Boolean
TRUE = new Boolean(true);
 public static final Boolean
FALSE = new Boolean(false);

 private final boolean value;

 public Boolean(boolean value)
 {
  this.value = value;
 }

 public boolean booleanValue()
 {
  return value;
 }

 public static Boolean valueOf(boolean b)
 {
  return (b ? TRUE : FALSE);
 }
}

- Т.е. класс просто является «оберткой» над типом boolean.

- Ага. А еще у него есть две константы TRUE и FALSE, которые являются аналогами примитивных значений true/false.

С автобоксингом у него тоже все просто:

КодЧто происходит на самом деле
Boolean a = true;
Boolean b = true;
Boolean c = false;
boolean d = a;
Boolean a = Boolean.valueOf(true);
Boolean b = Boolean.valueOf(true);
Boolean c = Boolean.valueOf(false);
boolean d = a.booleanValue();

А вот как происходят сравнения между типами boolean и Boolean:

Пример
boolean a = true;
Boolean b = true; //будет равен Boolean.TRUE
Boolean c = true; //будет равен Boolean.TRUE

a == b; //true (сравниваются как примитивы по значению)
a == c; //true (сравниваются как примитивы по значению)
b == c; //true (сравниваются по ссылке, но указывают на один и тот же объект)

Если очень нужно создать независимый объект Boolean, то надо создать его явно:

Пример
boolean a = true;
Boolean b = new Boolean(true); //новый объект Boolean
Boolean c = true; //будет равен Boolean.TRUE

a == b; //true (сравниваются как примитивы по значению)
a == c; //true (сравниваются как примитивы по значению)
b == c; //false (сравниваются по ссылке, указывают на различные объекты)

Собственно на этом все.

- Да, твои лекции покороче, чем у Билаабо.

А можно использовать Boolean внутри if ?

 
Boolean less = (2<3);
if (less)
{
….
}

- Да, только не забудь, что если less будет null, то выкинется исключение NullPointer.

- Да, я это уже понял. Только не держу все время в голове.

7. Задачи на автобоксинг Boolean

- Привет, Амиго!

Задачи
1. Странные ошибки О_о

Исправьте 2 ошибки:
1) возникновение исключения
2) подвисание
Сделайте минимальные изменения.
2. Особенности автобоксинга - 2

Исправьте ошибку реализации, приводящую к NullPointerException, в методе getValue.
Читайте доп. статью про особенности автобоксинга.

8. Character

- Привет, Амиго! Это снова я. Хотела тебе рассказать еще об одном достаточно простом классе-обёртке. Сегодня речь пойдет о Character – обертка над char.

Этот класс тоже довольно-таки прост.

Код
class Character
{
 private final char value;

 Character(char value)
 {
  this.value = value;
 }

 public char charValue()
 {
  return value;
 }

 static final Character cache[] = new Character[127 + 1];

 public static Character valueOf(char c)
 {
  if (c <= 127)
   return cache[(int)c];

  return new Character(c);
 }

 public int hashCode()
 {
  return (int)value;
 }

 public boolean equals(Object obj)
 {
  if (obj instanceof Character)
  {
   return value == ((Character)obj).charValue();
  }
  return false;
 }
}

В нем есть:

1) Конструктор, который принимает внутреннее значение и метод charValue, который его возвращает.

2) Метод valueOf, который возвращает новые объекты Character, но кэширует объекты со значениями от -128 до 127. Как в Integer, Short и Byte.

3) Методы hashCode() & equals – тут нас тоже ничем не удивишь.

А еще в нем есть много полезных методов (не показаны выше). Некоторые из них я тебе сейчас перечислю:

МетодОписание
boolean isDefined(char) Является ли символ символом Unicode?
boolean isDigit(char) Является ли символ цифрой?
boolean isISOControl(char) Является ли символ управляющим?
boolean isLetter(char) Является ли символ буквой?
boolean isJavaLetterOrDigit() Является ли символ буквой или цифрой?
boolean isLowerCase(char) Это символ в нижнем регистре (строчная буква)?
boolean isUpperCase(char) Это символ в верхнем регистре (заглавная буква)?
boolean isSpaceChar(char) Является ли символ пробелом или его аналогом (есть много невидимых символов)?
boolean isTitleCase(char) Является ли символ титульным?

- Спасибо, Ким, думаю, некоторые из этих методов мне точно пригодятся.

9. Задачи на автобоксинг Character

- Привет, Амиго!

Задачи
1. Этот странный BigDecimal

Исправьте ошибку реализации, приводящую к погрешности вычисления, в методе getValue.
Сигнатуру метода не менять. Округление не использовать.
Читайте доп. статью про особенности автобоксинга.
2. Кеширование

В CacheComputeManager реализуйте логику пустого метода.
Догадайтесь, что он должен делать по названию метода и по логике класса.

10. Void и др.

- Привет, Амиго! И снова маленькая и интересная тема. Тип Void.

- А зачем может понадобиться такой тип? Ну, c void-то понятно. Чтобы привести к общему знаменателю функции и процедуры. Теперь у нас нет процедур, зато есть функции, которые возвращают void (ничего).

- Ага. А ты помнишь, недавно Элли тебе рассказывала про интерфейс-шаблон Callable<T>?

- Ага.

- А что туда нужно передать в качестве типа-параметра тоже помнишь?

- Да, тип результата:

Пример задания, которое ничего не делает:
class EmptyJob implements Callable<String>
{
 public String call() throws Exception
 {
  return null;
 }
}

- Ага. А если тебе нужно, чтобы метод call возвращал значение int? Как тогда?

- Теперь я знаю, что для этого есть autoboxing. Я просто передам Integer, и все будет работать как часы:

Пример задания, которое ничего не делает:
class EmptyJob implements Callable<Integer>
{
 public Integer call() throws Exception
 {
  return null;
 }
}

- Отлично. А если метод ничего не должен возвращать?

- Я понял твою мысль. Тогда мы используем Void как аналог void?

- Ага.

- А не проще сделать просто Object и возвращать null.

- Иногда, но не всегда.

Ты знаешь, что там имелся в виду void, а ты написал Object, но другой программист может этого и не знать и будет думать, а почему это ты возвращаешь null.

Или код, вызывающий этот метод будет ожидать значения в качестве результата.

А когда написано Void то всем сразу понятно, что это – обертка над void, хотя возвращать null все же придётся.

Пример задания, которое ничего не делает:
class EmptyJob implements Callable<Void>
{
 public Void call() throws Exception
 {
  return null;
 }
}

- Гм. Действительно, метод, который всегда возвращает null, внушает некоторые сомнения. А метод, который объявлен Void, может это делать без лишних пояснений.

Читабельность кода - прежде всего. Мне нравится Java!

- Отлично. Рада, что тебе понравилось. На сегодня закончим.

11. Учимся гуглить. (Как настроить IDEA на определенные конвенции, Ctrl+Alt+L)

- Привет, Амиго!

Продолжаем наши уроки – учимся гуглить.

Вот тебе несколько заданий:

 Задания на поиск в интернете:
1 Как средствами Intellij IDEA переименовать(rename) переменную?
2 Как средствами Intellij IDEA сделать замену(replace) одного кода на другой?
3 Как средствами Intellij IDEA сделать так, чтобы переменная, на которой стоит курсор, подсвечивалась во всем коде?
4 Как средствами Intellij IDEA переименовать метод?
5 Как средствами Intellij IDEA переименовать класс?
6 Как средствами Intellij IDEA обернуть часть кода в try-catch?
7 Как средствами Intellij IDEA быстро создать конструктор?
8 Как средствами Intellij IDEA создать getter’ы и setter’ы?
9 Как средствами в Intellij IDEA реализовать (implements) недостающие методы класса?
10 Как средствами Intellij IDEA переопределить методы класса-родителя?

12. Профессор дает доп. материал

- Привет, Амиго!

Вот тебе дополнительный материал по теме.

Ссылка на дополнительный материал

13. Хулио

- Привет, Амиго. Ты почему такой грустный?

- Здравствуй. Не могу решить несколько задач.

- А знаешь что я делаю когда мне грустно?

- Что?

- Смотрю видео.

- Отличная идея.

Оригинал видео на YouTube

14. Вопросы к собеседованию по этой теме

- Привет, Амиго!

 Вопросы к собеседованиям
1 Что такое autoboxing?
2 Зачем используется autoboxing?
3 Альтернативы autoboxing?
4 Типы-обертки для примитивных типов mutable или immutable?
5 Как примитивные типы приводятся к непримитивным аналогам?
6 Как непримитивные типы приводятся к примитивным?
7 Как сравниваются примитивные и непримитивные типы?
8 Всегда ли создается новый объект при операции autoboxing?
9 Как работает кэширование при операции autoboxing?
10 Для каких типов и/или значений работает кэширование?

15. Большая задача

- Привет, Амиго!

- В секретных лабораториях проекта JavaRush уже разрабатываются сверхсложные задачи нового поколения. Как только задача будет закончена, отлажена и протестирована, тут появится ее условие. А пока немного подожди.