How can the map within java.util.HashSet become null [duplicate] - java

This question already has answers here:
Lazily initialize a Java map in a thread safe manner
(3 answers)
Closed 4 years ago.
I got NullPointerException at myset.contains(obj) and stacktrace like this:
java.lang.NullPointerException: null
at java.util.HashSet.contains(HashSet.java:203) ~[?:1.8.0_131]
I looked in to source code of HashSet,
private transient HashMap<E,Object> map;
...
202 public boolean contains(Object o) {
203 return map.containsKey(o);
204 }
so seems map is null, and my HashSet object is not.
But every init method of HashSet creates a HashMap Object and assigns to map, like
public HashSet() {
map = new HashMap<>();
}
So my question is, why can map become null in line 203?
This happens sometime in our web server, myset is used by multiple threads. I understand there could be inconsistent issue on a non-threadsafe HashSet, but I don't get why it became null.
Thanks in advance.
Post my code here:
Set<String> tags = data.getTags();
if (tags.contains(tmp.toString())) {
return true;
}
class definition of data, which is accessed by multiple threads:
class Data
private Set<String> tags;
public Set<String> getTags() {
if (tags == null) {
tags = new HashSet<String>();
// add something to tags
}
return tags;
}

I think there can be an issue with some other thread, because in this code, it will never change the map. It is just doing conatinsKey check, whoch will not alter the map.
You need to check which places (in various threads), changes are being done in the map, in order to verify that.

Related

How to modify an element of the Stream based on the value in a HashMap

I want to overwrite my objects status value if a corresponding key/value pair can be found in my HashMap.
Sample Model:
public class Url {
private String url;
private String status;
}
private List<Url> overwriteStatus(List<Url> myObjects) {
final var myChecklist = Map.of("www.foo.com", "blocked");
//if the key exists in `myChecklist`, then overwrite the status
myObjects.stream().forEach(item -> Optional.ofNullable(myChecklist.get(item.getUrl())).ifPresent(item::setStatus));
return myObjects;
}
My current approach with Optionals feels very messy.
What is the best approach to check if the value exists in a HashMap, and if so, use that value in a next step?
Documentation for the Stream API warns't against the usage of stateful streams.
Functions used in streams has to be pure, i.e. don't cause mutations of the stream elements, don't modify objects outside the stream (that's what basically happens in your code).
Your task can be fulfilled with streams without violating the guidelines mentioned above. For that, instead of changing the state if a new status has to be applied, a new object needs to be created.
I also suggest to Url objects immutable. So that the same instances could be safely reused in different parts of the application.
private List<Url> overwriteStatus(List<Url> myObjects,
Map<String, String> myChecklist) {
return myObjects.stream()
.map(item -> !myChecklist.containsKey(item.getUrl()) ? item :
new Url(item.getUrl(), myChecklist.get(item.getUrl())))
.collect(Collectors.toList());
}
Immutable class Url (no setters, all fields are final)
public class Url {
private final String url;
private final String status;
// constructor and getters
}
Note:
With regard to the Optional type, it was introduced in the JDK for only one particular purpose: to represent the return type of methods that could potentially yield null and that's it. The practice of utilizing the Optional just in order of chaining methods on it is considered to be an antipattern.
I don't think you should use a Stream since you are modifying the objects as you are iterating the collection.
Just use a loop
for (Url item : myObjects) {
String status = myCheckList.get(item.getUrl());
if (status == null) continue;
u.setStatus(status);
}

How can I rewrite null checks with optional in a better way [duplicate]

This question already has an answer here:
Java 8 avoiding null pointer checks using Optional
(1 answer)
Closed 1 year ago.
I am having a small snippet of code. I would like to write it in a better way with fewer nested checks. How can I achieve it?
Item item = itemResponse.getItem();
Optional<Item> optionalItem = Optional.ofNullable(item);
if (optionalItem.isPresent()) {
List<NameValue> listValues = item.getValues();
Optional<List<NameValue>> optionalListValues = Optional.ofNullable(listValues);
if (optionalListValues.isPresent()) {
System.out.println(listValues);
}
}
Is there any concise way I can rewrite the above piece of code using Java 8?
You can make itemResponse.getItem() class to return Optional<Item> and use the chained map method which will executed only if Optional has value, and if map method return non null value then only final ifPresent(Consumer consumer) is executed
Optional<Item> item = itemResponse.getItem()
item.map(item::getValues)
.ifPresent(System.out::println);

java.lang.UnsupportedOperationException when trying to delete from an #FXML TableView [duplicate]

This question already has answers here:
java.lang.UnsupportedOperationException for removing a row from the javafx tableview
(2 answers)
Closed 4 months ago.
I don't understand why this method wont work because it worked literally three days ago. Whenever I try to use the method(press the button), The database operations work fine but the program throws an error whenever I try to remove from the actual table view so that the user wont see that row anymore. I added a filtered list to the initialize method and i am concerned that might be the cause of the problem. Here is my code:
Initialize Method:
private void initialize()
{
ObservableList<BloomClient> clients = FXCollections.observableArrayList();
firstNames.setCellValueFactory(new PropertyValueFactory<>("FirstName"));
lastNames.setCellValueFactory(new PropertyValueFactory<>("LastName"));
phoneNumbers.setCellValueFactory(new PropertyValueFactory<>("PhoneNumber"));
birthdays.setCellValueFactory(new PropertyValueFactory<>("Birthday"));
startDates.setCellValueFactory(new PropertyValueFactory<>("StartDate"));
endDates.setCellValueFactory(new PropertyValueFactory<>("ExpireDate"));
try {
clients = dBconnect.getClientList();
} catch (Exception e) {
e.printStackTrace();
}
FilteredList<BloomClient> filteredList = new FilteredList<BloomClient>(clients,b -> true);
filteredSearch.textProperty().addListener(((observable, oldValue, newValue) ->
filteredList.setPredicate(person ->
{
if(newValue == null || newValue.isEmpty())
return true;//nothing in text field
String lowerCaseFilter = newValue.toLowerCase();
if (person.getFirstName().toLowerCase().contains(lowerCaseFilter))
return true;//check first name
else if (person.getLastName().toLowerCase().contains(lowerCaseFilter))
return true;//check last name
else
return false;
})
));
SortedList<BloomClient> sortedList = new SortedList<>(filteredList);
sortedList.comparatorProperty().bind(clientList.comparatorProperty());
clientList.setItems(sortedList);
}
public void freezeAccount() throws SQLException, ParseException {
BloomClient person = clientList.getSelectionModel().getSelectedItem();
dBconnect.sendToFreeze(person);//this works
dBconnect.deleteClient(person);//this works
clientList.getItems().remove(person);//java.lang.UnsupportedOperationException
clientList.refresh();
}
Well, it's just a guess. But it's possible that the clientList is a List<> type that was created using Collections.unmodifiableList(). When you try to modify one of those, an UnsupportedOperationException is thrown.
public static List unmodifiableList(List<? extends T> list)
Returns an unmodifiable view of the specified list. This method allows
modules to provide users with "read-only" access to internal lists.
Query operations on the returned list "read through" to the specified
list, and attempts to modify the returned list, whether direct or via
its iterator, result in an UnsupportedOperationException.
See: https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#unmodifiableList-java.util.List-
Figured it out in a way but would like a deeper explanation. I ended up instead of deleting from the clientList(TableView) I deleted directly from the clients(ObservableList) and made that variable global to be reached by other methods. I'm not sure of the reasoning behind the initial problem.
BloomClient person = clientList.getSelectionModel().getSelectedItem();
dBconnect.deleteClient(person);
clients.remove(person);
clientList.refresh();
}

Behavior of entrySet().removeIf in ConcurrentHashMap

I would like to use ConcurrentHashMap to let one thread delete some items from the map periodically and other threads to put and get items from the map at the same time.
I'm using map.entrySet().removeIf(lambda) in the removing thread. I'm wondering what assumptions I can make about its behavior. I can see that removeIf method uses iterator to go through elements in the map, check the given condition and then remove them if needed using iterator.remove().
Documentation gives some info about ConcurrentHashMap iterators behavior:
Similarly, Iterators, Spliterators and Enumerations return elements
reflecting the state of the hash table at some point at or since the
creation of the iterator/enumeration. hey do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.
As the whole removeIf call happens in one thread I can be sure that the iterator is not used by more than one thread at the time. Still I'm wondering if the course of events described below is possible:
Map contains mapping: 'A'->0
Deleting Thread starts executing map.entrySet().removeIf(entry->entry.getValue()==0)
Deleting Thread calls .iteratator() inside removeIf call and gets the iterator reflecting the current state of the collection
Another thread executes map.put('A', 1)
Deleting thread still sees 'A'->0 mapping (iterator reflects the old state) and because 0==0 is true it decides to remove A key from the map.
The map now contains 'A'->1 but deleting thread saw the old value of 0 and the 'A' ->1 entry is removed even though it shouldn't be. The map is empty.
I can imagine that the behavior may be prevented by the implementation in many ways. For example: maybe iterators are not reflecting put/remove operations but are always reflecting value updates or maybe the remove method of the iterator checks if the whole mapping (both key and value) is still present in the map before calling remove on the key. I couldn't find info about any of those things happening and I'm wondering if there's something which makes that use case safe.
I also managed to reproduce such case on my machine.
I think, the problem is that EntrySetView (which is returned by ConcurrentHashMap.entrySet()) inherits its removeIf implementation from Collection, and it looks like:
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
// `test` returns `true` for some entry
if (filter.test(each.next())) {
// entry has been just changed, `test` would return `false` now
each.remove(); // ...but we still remove
removed = true;
}
}
return removed;
}
In my humble opinion, this cannot be considered as a correct implementation for ConcurrentHashMap.
After discussion with user Zielu in comments below Zielu's answer I have gone deeper into the ConcurrentHashMap code and found out that:
ConcurrentHashMap implementation provides remove(key, value) method which calls replaceNode(key, null, value)
replaceNode checks if both key and value are still present in the map before removing so using it should be fine. Documentation says that it
Replaces node value with v, conditional upon match of cv if
* non-null.
In the case mentioned in the question ConcurrentHashMap's .entrySet() is called which returns EntrySetView class. Then removeIf method calls .iterator() which returns EntryIterator.
EntryIterator extends BaseIterator and inherits remove implementation that calls map.replaceNode(p.key, null, null) which disables conditional removal and just always removes the key.
The negative course of events could be still prevented if iterators always iterated over 'current' values and never returned old ones if some value is modified. I still don't know if that happens or not, but the test case mentioned below seems to verify the whole thing.
I think that have created a test case which shows that the behavior described in my question can really happen. Please correct me if I there are any mistakes in the code.
The code starts two threads. One of them (DELETING_THREAD) removes all entries mapped to 'false' boolean value. Another one (ADDING_THREAD) randomly puts (1, true) or (1,false) values into the map. If it puts true in the value it expects that the entry will still be there when checked and throws an exception if it is not. It throws an exception quickly when I run it locally.
package test;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
public class MainClass {
private static final Random RANDOM = new Random();
private static final ConcurrentHashMap<Integer, Boolean> MAP = new ConcurrentHashMap<Integer, Boolean>();
private static final Integer KEY = 1;
private static final Thread DELETING_THREAD = new Thread() {
#Override
public void run() {
while (true) {
MAP.entrySet().removeIf(entry -> entry.getValue() == false);
}
}
};
private static final Thread ADDING_THREAD = new Thread() {
#Override
public void run() {
while (true) {
boolean val = RANDOM.nextBoolean();
MAP.put(KEY, val);
if (val == true && !MAP.containsKey(KEY)) {
throw new RuntimeException("TRUE value was removed");
}
}
}
};
public static void main(String[] args) throws InterruptedException {
DELETING_THREAD.setDaemon(true);
ADDING_THREAD.start();
DELETING_THREAD.start();
ADDING_THREAD.join();
}
}

Many readers but not when writer available with HashMap java

I've crawl through many question regarding this area but my question still remains with me. I'm seeking some elaborate answer as well(If you kind enough?). So i could understand this more clearly and community as well.
This is my question. I have this map.
private static volatile Map<Integer, Type> types;
and have static getter as,
static Type getType(final int id)
{
if (types == null)
{
synchronized (CLASSNAME.class)
{
if (types == null)
{
types = new HashMap<Integer, Type>();
....add items to the map
}
}
}
return types.get(id);
}
Problem in this code is first thread can initialize the types so it won't be null anymore. While first thread adding values to map second thread can retrieve data from it. That means corrupted data.
I see that this can be avoid by synchronizing whole method but then multiple readers is not possible. It's an one time construction for that map and there will be no modification. So multiple readers is essential.
Also we can use Collections.synchronizeMap but if i'm correct it also not allowing concurrent readers. I tried but ConcurrentHashMap doesn't solve this either. Maybe due to it's independent partition locking behavior.
Simply what i need is no reading until map created fully and then multiple read should be possible.
Anyone got a solution?
Thanks.
There is a simple solution to your problem. Use a temporary variable, so that the reference types is null as long as the map is not completely populated. If you change the code in that way, it is thread-safe and quite efficient.
static Type getType(final int id) {
if (types == null) {
synchronized (CLASSNAME.class) {
if (types == null) {
HashMap<Integer, Type> temp = new HashMap<>();
// populate temp
types = temp;
}
}
}
return types.get(id);
}
Thread-safe, lazy and efficient initialization is a frequently required feature. Unfortunately, it's not directly supported by Java, neither by the programming language nor by the standard library. Instead, there are different patterns, and your implementation is known as Double-checked locking.
A short excursion to C++: C++11 has support for lazy, thread-safe initialization both in the language and in the library. If there is only one global type mapping, you can write the following in C++:
auto populated_map()
{
std::map<int, type> result;
// ... populate map
return result;
}
auto get_type(int id) -> const type&
{
static const std::map<int, type> map = populated_map();
return map.find(id)->second;
}
If you need lazy initialization per object, you can use the library support around std::once_flag and std::call_once:
class types
{
private:
std::once_flag _flag;
std::map<int, type> _map;
public:
auto get_type(int id) -> const type&
{
std::call_once(_flag, [this] { _map = populated_map(); });
return _map.find(id)->second;
}
};
Take a look into the Memoization pattern. There are specific implementations available in Java 8 but if you aren't adopting that soon, look at Guava's MapMaker, specifically:
private final ConcurrentMap<Map<Integer, Type> types = new MapMaker()
.makeComputingMap(new Function<Integer, Type>() {
public Graph apply(Type key) {
return loadForType(key);
}
});
In this case, no one thread will be populating this map (it may be that a single thread does). The idea is, when a thread enters it will check to see if a value for any Integer is available. If not it will run the function once, if it is, it will return it while not blocking

Categories