Я действительно не знаю, что интервьюер ищет в этом вопросе интервью

Java

Интервью — очень странный процесс, это все пиздец. Но все вопросы о том, как построить ракету: один смеет спрашивать, а другой осмеливается отвечать.

Интервью — это не страшно, ужасно то, что вы не можете понять точку зрения интервьюера.

Что еще хуже, вы чувствуете, что знаете ответ, но не то, что хочет интервьюер.

Самое страшное, что интервьюер не знает, каков ответ на этот вопрос.

Отправить подвопрос? Отправить предложение?

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

file

Представьте немного неловкую картину:

Интервьюер: Почему ключ в ConcurrentHashMap не может быть нулевым?

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

Интервьюер: Больше нет?

Интервьюер: Нет больше.

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

Что произошло, вы узнаете после прочтения этой статьи.

Позвольте мне уточнить и поднять этот вопрос интервью, пожалуйста:

Почему ConcurrentHashMap не может хранить нулевое значение?

Почему ConcurrentHashMap не может поместить ключ, значение которого равно null?

SHOW ME THE CODE

Давайте сначала посмотрим, каков результат выполнения программы, когда ключ и значение ConcurrentHashMap равны нулю:

file

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

Соответствующая часть исходного кода выглядит следующим образом (JDK 1.8):

file

Иногда, когда вы видите исходный код, это означает, что вы внимательно прочитали;

Иногда, когда вы видите исходный код, вы видите только внешний вид.

Например, в этом месте, почему исходный код написан именно так? Или, другими словами, с какой целью автор это написал?

if (key == null || value == null) throw new NullPointerException();

Чтобы узнать, какова отправная точка автора, наиболее авторитетным ответом является собственный ответ автора. ConcurentHashMap был написан гигантом Дугом Ли.

file

Кто такой Дуг Ли? Вы знаете пакет java.util.concurrent? он написал.

Как говорится: если вы не знаете программирования Дуга Ли, писать на Java бесполезно.

file

Ах, почему старик такой сильный и у него такие волосы.

file

Теперь, когда вы знаете, кто он, легко сделать следующее. Потому что еще в 2006 году кто-то написал электронное письмо, чтобы узнать, почему ключ и значение ConcurrentHashMap не могут быть нулевыми, и его отец лично ответил на этот вопрос.

В процессе перевода четырех связанных электронных писем эта статья объединяет электронные письма старика и мое собственное понимание, чтобы ответить на этот вопрос.

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

Первое письмо: Тутика в помощь

Адрес электронной почты:В это время.Oswego.quote/Piper mail/от…

В 06:01:45 утра 12 мая 2006 г. пользователь сети по имени Тутика отправил электронное письмо с просьбой о помощи:

file

Содержание письма следующее:

file

Полный текст переведен, вероятно, следующим образом:

Всем привет, я хочу заменить некоторые HashMaps в многопоточном проекте на ConcurrentHashMaps. В HashMap я могу без проблем поместить данные, ключ или значение которых равно null. Но ключ и значение ConcurrentHashMap не могут быть нулевыми.

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

Мое решение состоит в том, чтобы обернуть ConcurrentHashMap, заменить его другим объектом при вставке нулевого значения и преобразовать его в нуль при извлечении объекта. Но проблема с этим решением заключается в том, что очень сложно выполнять соответствующие преобразования в пакетных операциях, таких как keySet() и values().

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

Перевод окончен.

Здесь я хотел бы добавить отступление: что касается искусства задавать вопросы, я думаю, что метод вопросов Тутики очень стандартный. С какой проблемой вы столкнулись в каком сценарии, какое решение вы пробовали и есть ли лучшее решение?

Внимательно посмотрите на картинку ниже, не подходите и не говорите: "Есть кто-нибудь? Есть?"

file

Второе письмо: восторженные пользователи сети

Адрес электронной почты:В это время.Oswego.quote/Piper mail/от…

Через час, 20 минут и 18 секунд после того, как Тутика отправил электронное письмо «SOS», восторженный пользователь сети Хольгер ответил на его вопрос:

file

Полный текст оригинальной версии выглядит следующим образом:

file

file

file

Позвольте мне перевести это снова:

Тутика: Я хочу заменить некоторые HashMaps в многопоточном проекте на ConcurrentHashMaps.

Хольгер: Прежде чем сделать это, вы должны понять, что, хотя такое решение может показаться способным решить вашу проблему, оно может дать вам неожиданные результаты. Некоторые скрытые причины, они могут проявляться в виде ConcurrentModificationException. Лучше решить проблему параллельного доступа, чем маскировать проблему с помощью ConcurrentHashMap, потому что после того, как эта очевидная проблема будет «исправлена», вы, вероятно, столкнетесь с другими ошибками из-за параллелизма.

Тутика: Я могу без проблем поместить данные, ключ или значение которых равно null, в hashMap.

Хольгер считает, что возможность хранить null в HashMap — серьезная ошибка класса Java Map.

Тутика: Но ключ и значение ConcurrentHashMap не могут быть нулевыми. Я хотел бы знать, есть ли у кого-нибудь лучший способ решить эту проблему.

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

Тутика: В моем приложении очень сложно определить значение и ключ, которые являются нулевыми.

Хольгер: Это цена, которую приходится платить за использование HashMap, допускающего нулевые значения.

Тутика: я хочу обернуть ConcurrentHashMap, заменить его другими объектами при вставке нулевого значения и преобразовать его в нуль, когда объект будет извлечен. Но проблема с этим решением заключается в том, что в методах пакетных операций, таких как keySet(), values(), преобразование значений очень затруднено.

Хольгер: Тем не менее, у вас все еще есть проблема: сначала вам нужно найти все вызывающие объекты существующих конструкторов карты и исправить их. И это тоже невозможно, например, вы можете получить эту Карту из других мест.

Tutika: Если у кого-то есть решение этой проблемы, пожалуйста, дайте мне знать. Это будет очень полезно для меня.

Хольгер предлагает следующие два варианта:

1. Прежде всего, вы должны признать, что ваша программа имеет проблемы с параллелизмом.Вы должны найти причину проблемы, вместо того, чтобы пытаться скрыть проблему с помощью ConcurrentHashMap. Это просто сигнал о том, что что-то еще не так. Это означает, что вы должны выполнить адекватный анализ параллелизма всего приложения или затронутых подсистем (если таковые имеются), а также это означает, что вы должны критически взглянуть на то, где в вашем приложении происходит параллельный доступ. Найдя его, вы можете использовать Collections.synchronizedMap() или ConcurrentHashMap для его решения.

2. Используйте технологию АОП для решения вашей проблемы. Я приложил простой аспект AspectJ MapCheck, который вы можете вплести в свое приложение. В моем примере выбрасываются IllegalArgumentExceptions, конечно, вы можете изменить его, чтобы пропустить эту операцию ввода в соответствии с вашим сценарием, или поставить значение по умолчанию. Вам нужно серьезно оценить, подходит ли это для вашего сценария, потому что, когда вызывающая сторона по ошибке передает пустой ключ, вы можете в конечном итоге заменить значение ключом по умолчанию. Аспект, который я даю, заключается в том, чтобы выявить проблему нулевого ключа/значения на ранней стадии. В вашем бизнес-сценарии может быть приемлемо пропустить эту операцию.

file

В заключение, нет быстрого решения вашей проблемы.

Перевод окончен.

Позвольте мне резюмировать то, что сказал этот приятель Хольгер:

1. В вашей программе есть проблемы с параллелизмом Простое введение ConcurrentHashMap — единственный способ устранить симптомы, а не основную причину.

2. Разрешать ключи/значения с нулевыми значениями в HashMap — это неправильный дизайн.

3. Решение, которое вы дали, плохое.

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

5. Либо вы используете технологию АОП для решения своей задачи, хотя я этого не рекомендую, но я все же пишу вам пример, здесь я бросаю исключение, вы можете проанализировать его по конкретной ситуации вашего бизнес-сценария.

6. С вашим вопросом не очень легко разобраться, здесь я могу только помочь.

Третье письмо: великан появился

Адрес электронной почты:В это время.Oswego.quote/Piper mail/от…

Через 2 часа и 47 секунд после того, как Тутика отправил электронное письмо с сигналом бедствия,

file

На этот вопрос лично ответил автор ConcurrentHashMap мистер Дуг. Это основной момент этого вопроса и основной момент этой статьи.Полный текст выглядит следующим образом:

file

file

перевести:

Тутика: Я хочу заменить некоторые HashMaps в многопоточном проекте на ConcurrentHashMaps. В hashMap я могу без проблем поместить данные, ключ или значение которых равно null. Но ключ и значение ConcurrentHashMap не могут быть нулевыми. Что касается электронного письма от восторженного пользователя сети Хольгера, Дуг сказал: Вы можете попытаться принять совет Хольгера, хотя он не дошел до сути...

На вопрос, заданный Tutika, ответ Дага таков: Основная причина, по которой нулевые значения не допускаются в контейнерах, учитывающих безопасность параллелизма, таких как ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps), заключается в том, что в случае параллелизма он может привнести недопустимую двусмысленность. В непараллельно-безопасном контейнере такая проблема может быть решена. В контейнере карты значение, полученное при вызове метода map.get(key), равно null, тогда вы не можете судить о том, был ли ключ не сопоставлен на карте или ключ вообще не существует на карте. В этом случае на карте, не поддерживающей параллелизм, вы можете использовать метод map.contains(key) для определения. Но в карте, которая учитывает безопасность параллелизма, это значение может быть изменено между вызовами.

Далее Дуг сделал отступление: лично я считаю, что разрешение нулевых значений в коллекциях Maps или Sets — это открытое приглашение к ошибкам в вашей программе. И эти ошибки можно найти только тогда, когда ошибка возникает. (Я думаю, что вопрос о том, следует ли разрешать пустые значения в картах и ​​наборах, не поддерживающих параллелизм, является одним из немногих вопросов дизайна наборов, и мы с Джошем Блохом спорим по этому поводу в течение долгого времени.)

Тутика: Во всем моем приложении очень сложно судить о значении и ключе значения null.

Предложение Дуга: попробуйте где-нибудь объявить static final Object NULL=new Object(), а затем заменить все места с null на NULL.

Перевод окончен.

Позвольте мне проанализировать то, что сказал мистер Дуг.

Сначала он высмеял совет Хольгера: его советом можно было воспользоваться, но он не дошел до сути.

Говоря об основной причине, Даг использовал метод доказательства от противного, сначала предположив, что ConcurrentHashMap также может хранить значения, значение которых равно null. При вызове map.get(key), будь то HashMap или ConcurrentHashMap, если возвращается null, то этот null имеет два значения:

**1. Этот ключ никогда не отображался на карте.

** 2. Когда значение этого ключа установлено, оно равно нулю.

Он сказал, что метод map.contains(key) может быть использован для определения не потокобезопасной коллекции карт (HashMap), но ConcurrentHashMap не может.

Я использую программу, чтобы выразить его конкретное значение.

Прежде всего, давайте сначала поговорим о HashMap, потому что HashMap не является потокобезопасным (добавьте ерунду: если вы только читаете, а не пишете, HashMap также является потокобезопасным), поэтому наш правильный сценарий использования HashMap — использовать его под одиночная нить. следующее:

file

Результат:

file

В приведенном выше примере, поскольку это один поток, когда значение, которое мы получаем, равно нулю, я могу использовать метод hashMap.containsKey(key), чтобы различить два упомянутых выше значения.

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

Таким образом, когда значение, возвращаемое map.get(key), равно null, несмотря на наличие неоднозначности в HashMap, неоднозначности можно избежать, объединив метод containsKey.

А как насчет ConcurrentHashMap, сценарий его использования многопоточный. Мы по-прежнему используем противоположный метод, предполагая, что concurrentHashMap позволяет сохранить значение null.

В это время есть два потока A и B.

Поток A вызывает метод concurrentHashMap.get(key) и возвращает значение null Мы до сих пор не знаем, является ли значение null несопоставленным значением null или сохраненное значение равно null.

Мы предполагаем, что реальная ситуация возврата null в настоящее время связана с тем, что ключ не был отображен в карте. Затем мы можем использовать concurrentHashMap.containsKey(key), чтобы проверить, верно ли наше предположение, и наш ожидаемый результат должен вернуть false.

Но после вызова метода concurrentHashMap.get(key) и перед методом containsKey существует поток B, который выполняет операцию concurrentHashMap.put(key,null). Затем мы вызываем метод containsKey, чтобы вернуть значение true. Это не соответствует нашей гипотетической реальности.

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

Вышеприведенное также является ответом Дуга на этот вопрос интервью (почему значение в ConcurrentHashMap не может быть нулевым).

Но прямого ответа на вопрос, почему ключ не может быть нулевым, не дается.

В конце письма Дуг дал свое собственное предложение по проблеме, с которой столкнулась Тутика: вы можете определить глобальный объект с именем NULL. Когда вам нужно использовать нулевое значение, используйте этот NULL, чтобы заменить его на false.

При этом он также выразил в письме свое личное мнение: он считает, что независимо от того, учитывает ли контейнер вопросы безопасности потоков, нельзя допускать появления нулевых значений. Он считает, что разрешение нулевых значений в некоторых существующих коллекциях — это проблема дизайна коллекций. Он также обсуждал это с Джошем Блохом.

тогда этоJosh BlochКто это?

file

file

file

В записи упоминается книга «Эффективная Java», которую я лично считаю библией для Java. Если вы не знаете, я призываю вас прочитать ее и положить рядом с подушкой. В то же время он также является одним из авторов HashMap, поэтому имеет право голоса в HashMap.

И, ах, почему он такой сильный и у него столько волос.

Четвертое письмо: Джош отвечает

Адрес электронной почты:В это время.Oswego.quote/Piper mail/от…

После того, как Дуг указал свои 4 часа 19 минут и 34 секунды в электронном письме, Джош также отправил электронное письмо:

file

Содержание письма следующее:

file

В электронном письме Джоша говорилось: Даг, я был на твоей стороне все эти годы. На самом деле может быть ошибкой разрешать нулевые ключи в коллекциях Карт и нулевые элементы в наборах. Но я все еще думаю о том, следует ли допускать существование значения со значением null.

Кроме того, Джош пытается сказать, что Дуг ненавидит null больше, чем он. Но с годами он также обнаружил, что null — очень неприятная проблема.

Позвольте мне интерпретировать то, что Джош хочет выразить:

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

2. Дуг, ты прав, нуль - это действительно головная боль.

Возможно, от Джоша я могу понять, почему ключ concurrentHashMap не может быть нулевым. Поскольку Дуг ненавидит нулевые значения, в сочетании с собственными словами Дага, он считает, что дизайн, допускающий нуль, неразумен: (Он написал здесь нули, я понимаю, что ни ключ, ни значение не могут быть нулевыми.)

file

Как ответить?

Итак, как же ответить на вопрос, поставленный в начале статьи?

Если интервьюер спросит, почему значение ConcurrentHashMap не может быть нулевым? Такие вопросы на собеседовании по-прежнему имеют смысл, потому что с ним все еще можно говорить о двусмысленности. Это показывает, что у вас есть некоторые мысли о ConcurrentHashMap.

Но интервьюер спросил, почему ключ concurrentHashMap не может быть нулевым? Как я писал в начале статьи, прочитав эти письма, я до сих пор не знаю, что ответить.

Как я могу ответить?

Мой ответ заключается в том, что исходный код написан так? Ответ одним предложением, интервьюер не удовлетворен. Затем я сказал, что поскольку автору Дугу не нравился нуль, существование нулевых ключей не допускалось в начале дизайна. Если бы интервьюер ожидал такого ответа, не был бы этот вопрос слишком предвзятым?

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

file

Последнее слово

Эта статья, извлеченная точка знаний - очень маленькая точка, но почему я написал более 7000 слов с размахом?

Потому что я думаю, что то, что я извлек, является сморщенным знанием, оно недостаточно богато, и в нем нет процесса исследования.

И то, что я показываю, — это мой процесс поиска ответа на этот вопрос. Через содержание четырех электронных писем причина и следствие связаны друг с другом, и личный ответ автора чрезвычайно авторитетен.

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

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

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

Спасибо за прочтение и за внимание.

выше.

Добро пожаловать в публичный аккаунт [почему технология] и настаивайте на выводе оригинальности. Пусть мы с тобой прогрессируем вместе.

公众号-why技术