Interviewing is a weird process. It’s all about turning the screw. But all the questions were about how to build a rocket.
The interview is not scary, the scary thing is that you can’t get the interviewer’s point.
Even scarier is when you think you know the answer, but it’s not what the interviewer wants.
The scariest part is that the interviewer doesn’t know the answer.
Send questions? Proposition?
A few days ago, a friend shared an interview question from his own experience in a group. At first glance, this question seems to be easy to answer, but after careful consideration, is this the answer the interviewer wants? You can see the screenshot.
Imagine the slightly awkward scene:
Interviewer: Excuse me, why can’t the key in ConcurrentHashMap be null?
Interviewer: Because it is written in the source code, it is judged to be empty and an exception is thrown.
Interviewer: No?
Interviewer: No.
I thought a lot about it, and I really didn’t know what the interviewer was looking for. Even after I’ve written this article and I know the cause and effect, I still don’t know how to answer his question. Because I can’t find out where his dots are.
After reading this article, you will know exactly what happened.
Let me refine and refine this interview question:
ConcurrentHashMap Why cannot a value with a null value be stored?
ConcurrentHashMap Why can’t you put a null key?
SHOW ME THE CODE
If ConcurrentHashMap’s key and value are null, let’s see what happens when ConcurrentHashMap’s key and value are null.
As you can see, this throws a null pointer exception because neither the key nor the value in ConcurrentHashMap can be null.
The corresponding source code is as follows (JDK 1.8) :
Sometimes, when you see the source code, it means you’re looking deep.
Sometimes, you see the source code, just the surface.
For example, in this place, why is the source code written this way? Or, to put it another way, what is the author thinking about?
if (key == null || value == null) throw new NullPointerException();
To know what the author is writing from, the most authoritative answer is the author’s own answer. The ConcureentHashMap was written by Doug Lea.
Who is Doug Lea? You know the java.util.Concurrent package? He has written.
As the saying goes: If you can’t program Doug Lea, you can’t write Java.
Oh, why is pops so strong and so much hair.
Now that we know who he is, it’ll be easy. In 2006, someone wrote an email asking why the key and value of ConcurrentHashMap could not be null, and he answered the question himself.
In the process of translating four related emails, this paper combines pops’ email with my own understanding to answer this question.
Explanation: my English level is limited, translated out of the article we see a lot of tolerance. I have attached the original text and email address for you to visit.
The first: Tutika for help
Email address: cs.oswego.edu/pipermail/c…
On May 12, 2006, at 6:01am and 45 seconds, a netizen named Tutika sent an email asking for help:
The email is as follows:
The full text of the translation, roughly:
Hi, I want to replace some of the hashmaps in one of my multi-threaded projects with concurrenthashMaps. I can put a null key or value in a HashMap without any problems. However, the key and value of ConcurrentHashMap cannot be null.
I want to know if there is a better way to solve this problem. It should be noted that in my application, it is very difficult to determine the value and key that are null.
My solution is to wrap the ConcurrentHashMap so that when null is inserted it is replaced by another object, and when null is retrieved it is converted to null. The problem with this solution, however, is that it is very difficult to perform the corresponding transformation in batch operation methods such as keySet(), values().
If anyone has ideas for this problem, please let me know. This will be very useful to me.
End of translation.
I want to make an aside here about the art of asking questions, and I think Tutika’s way of asking questions is pretty standard. Under what circumstances did you encounter any problems? What is the solution you tried? Is there a better solution?
Take a good look at the picture below. Don’t start with: Hello? In?
The second: enthusiastic net friend
Email address: cs.oswego.edu/pipermail/c…
An hour, 20 minutes and 18 seconds after Tutika sent his “SOS” email, an avid user named Holger responded to his question,
The full text of the original is as follows:
Let me translate again:
Tutika: I want to replace some of the hashmaps in one of my multi-threaded projects with concurrenthashMaps.
Holger: Before you do that, you must understand that while such a solution may seem like a solution to your problem, it may have unexpected consequences. Some hidden deep reason, they may be represented by such as ConcurrentModificationException. It is better to solve the concurrent access problem rather than mask the problem with ConcurrentHashMap, because after this obvious problem has been “fixed”, you are likely to encounter other bugs caused by concurrency.
Tutika: I can put a null key or value in a hashMap without any problems.
Holger believes that the ability to store null in a HashMap is a serious error in the Java Map class.
Tutika: But the key and value of ConcurrentHashMap cannot be null. I wonder if anyone has a better way to solve this problem.
Holger’s suggestion is to add logic to the caller to check that neither key nor value is null. If you have unit tests, please include tests for this logic in your tests.
Tutika: In my application, it is very difficult to identify values and keys that are null.
Holger: That’s the price you pay for using a HashMap that allows nulls.
Tutika: I want to wrap the ConcurrentHashMap so that when null is inserted it is replaced by another object, and when null is retrieved it is converted to null. The problem with this solution, however, is that it is very difficult to convert values in batch-based methods such as keySet() and values().
Holger: Even then, you still run into the problem of first finding all the callers of the existing Map’s constructor and fixing them. It’s also impossible, for example, to get the Map from somewhere else.
Tutika: Let me know if anyone has a solution to this problem. This will be very useful to me.
Holger offers the following two options:
1. First of all, accept that your program has a concurrency problem, and you need to find the cause of the problem instead of trying to cover it up with ConcurrentHashMap. It’s just a sign that something else is wrong. This means that you need to perform adequate concurrency analysis on the entire application or affected subsystems (if any). It also means that you must take a hard look at where concurrent access exists in your application. Find you can then use the Collections. SynchronizedMap () or ConcurrentHashMap to solve.
Use AOP to solve your problem. I’ve added a simple AspectJ MapCheck aspect that you can weave into your application. In my example is thrown IllegalArgumentExceptions, of course, you can skip this time according to your scene changed to put operations, or the default value. You need to evaluate very carefully whether this is appropriate for your scenario, because when the caller mistakenly passes an empty key, you may end up replacing the value with the default key. The aspect I gave you is to expose the empty key/value problem as early as possible. In your business scenario, it may be acceptable to skip this operation.
In short, there is no shortcut to your problem.
End of translation.
Let me summarize what this guy Holger said:
1. You have concurrency problems with this program, and just introducing ConcurrentHashMap is a palliative.
2. Allowing null keys/values in a HashMap is a bad design.
3. Your solution is bad.
4. My advice to you is to find the part where you have concurrency problems that you don’t control well. Get to the root of the problem.
5. Or you can use AOP to solve your problem. I don’t recommend it, but I’ll give you an example.
You have a difficult problem. I can only help you so far.
Third: the big guy appeared
Email address: cs.oswego.edu/pipermail/c…
Two hours and 47 seconds after Tutika sent the SOS email,
Doug, the author of ConcurrentHashMap, answers the question himself. This is the highlight of this question, and also of this article, which is as follows,
Translation:
Tutika: I want to replace some of the hashmaps in one of my multi-threaded projects with concurrenthashMaps. I can put a null key or value in a hashMap without any problems. However, the key and value of ConcurrentHashMap cannot be null. You can try taking Holger’s advice, Doug. He doesn’t get the point.
Doug’s answer to Tutika’s question is: The main reason that null values are not allowed in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) containers for concurrency security is that they can create intolerable ambiguity in the case of concurrency. In a non-concurrency-safe container, this problem is solvable. Get (key) is null in a map, so you can’t tell if the key is not mapped in the map, or if it doesn’t exist in the map at all. In this case, in a non-concurrent secure map, you can tell by the map.contains(key) method. But in a map that considers concurrency security, it is possible for this value to change between calls.
In my opinion, allowing null values in Maps or Sets is an open invitation to errors into your application. These errors, however, can only be detected if they occur. (I think the question of whether or not to allow null in non-concurrent secure Maps and Sets is one of the few design issues with collections, and one that Josh Bloch and I have been arguing about for a long time.)
Tutika: In my entire application, it’s very difficult to identify values and keys that are null.
Static final Object NULL=new Object(), NULL=new Object(), NULL=new Object(), NULL=new Object()
End of translation.
Let me break down what Pops Doug said.
First he makes a joke about Holger’s suggestion: you can use his advice, but he misses the point.
Doug: ConcurrentHashMap can also store null values. Doug: ConcurrentHashMap can also store null values. Get (key) ¶ If null is returned when a HashMap or ConcurrentHashMap calls map.get(key), then null has two meanings:
**1. This key has never been mapped in the map.
**2. The value of this key is null when set.
He says the map.contains(key) method can be used in a non-thread-safe map set (HashMap), but ConcurrentHashMap cannot.
Let me show you what he means programmatically.
First of all, HashMap, since HashMap is thread unsafe (a little bit of nonsense: HashMap is also thread safe if it is read only and not written), the correct scenario for our use of HashMap is to use it under a single thread. As follows:
The output is:
In the example above, since it is single-threaded, I can use the hashMap.containskey (key) method to distinguish between the two meanings when we get null.
By following the above procedure, the first judgment shows that the key has never been mapped in the map. The second judgment shows that the value of this key, when set, is null.
So when map.get(key) returns null, there is some ambiguity in HashMap, but it can be avoided with containsKey.
But what about ConcurrentHashMap? It is used in multithreaded situations. Let’s assume that concurrentHashMap allows null values to be stored.
There are two threads, A and B.
Thread A calls the concurrenthashMap.get (key) method and returns null. We still don’t know whether the null is unmapped or the stored value is null.
We assume that the true case of null is because the key is not mapped in the map. So we can use a concurrentHashMap. Either containsKey (key) to verify whether our hypothesis, we expect the result is false.
But after we call concurrenthashMap.get (key) and before containsKey, there is thread B that executes concurrenthashMap.put (key,null). So if we call containsKey it will return true. This is not consistent with our hypothesis.
The map might have changed between calls. The map might have changed between calls. That’s the ambiguity that Doug is talking about.
That’s Doug’s answer to the interview question why value in ConcurrentHashMap is not allowed to be null.
But there is no direct answer as to why the key cannot be null.
At the end of the message, Doug gave his own suggestion for Tutika’s problem: you could define a global Object with the name NULL. When a null value is needed, use this null instead to make it look like a real one.
In the email, he also expressed his personal opinion that null values should not be allowed, whether or not the container is concerned with thread safety. He thinks that allowing null values in some existing sets is a design problem. He’s been talking to Josh Bloch about it.
So who is Josh Bloch?
The entry mentions a book called Effective Java, which I personally consider the bible of the Java world. If you don’t know, I urge you to read it and keep it on your pillow. He’s also one of the authors of HashMap, so he has a lot to say about it.
And, ah, why is he so strong and has so much hair.
Fourth email :Josh responds
Email address: cs.oswego.edu/pipermail/c…
Four hours, 19 minutes and 34 seconds after Doug cue him in the email, Josh sends his own:
The email is as follows:
Josh’s email said: Doug, I’ve been in your shoes for years. Allowing null keys in Maps Sets and allowing null elements in Sets may indeed be an error. But I’m still thinking about whether we should allow null values to exist.
In addition, What Josh is trying to say is that Doug hates null even more than he does. But over the years, he has also found null to be a major headache.
Here’s what Josh is trying to say:
Doug, you’re barking up the wrong tree. You shouldn’t have used the word “fight” to describe our problems. I’m half okay with your point.
2.Doug, you’re right. Null is a real headache.
Maybe, from Josh, I can get why the key of concurrentHashMap cannot be null. Doug hates nulls. Doug says he doesn’t think it’s reasonable to allow nulls.
What’s the answer?
So, what is the answer to the question raised at the beginning of the article?
If the interviewer asks why the ConcurrentHashMap value cannot be null? This is a good interview question, because you can still have some ambiguity with him. It shows that you have some thought about ConcurrentHashMap.
But the interviewer asked why the key of concurrentHashMap cannot be null? As I said at the beginning of my article, I still don’t know how to answer these emails after reading them.
What can I say?
I said that’s how the source code is written? In one sentence, the interviewer was not satisfied. Doug doesn’t like null, so he didn’t allow null keys at the beginning of the design. If this is what the interviewer is expecting, isn’t this a little off the mark?
So I think this question can be anecdote, but to force as an interview question, I think it’s a little far-fetched.
One last thing
This article, the knowledge points extracted is a very small point, but why DID I write more than 7000 words in great detail?
Because I feel what extract comes out, it is a dry pimp knowledge point, it is not rich enough, without the process of exploration.
And what I’m showing is how I went about finding the answer to that question. Through the contents of four emails, the author’s answer is authoritative.
This article not only exercises my logical reasoning ability, but also exercises my English translation ability, which is a great help to me.
I will always be the first reader of my articles. I will only write what I think is good and helpful to me. Because what has helped me so much will help you a little.
If you find something wrong, please leave me a message to point it out so that I can modify it.
Thank you for reading and for your attention.
The above.
Welcome to pay attention to the public number [Why Technology], adhere to the output of original. May you and I make progress together.