I'm trying to create a custom Itemreader using a HashMap, here is an eaxmple i find it of an itemReader using a list instead of HashMap
public class InMemoryStudentReader implements ItemReader<StudentDTO> {
private int nextStudentIndex;
private List<StudentDTO> studentData;
InMemoryStudentReader() {
initialize();
}
private void initialize() {
StudentDTO tony = new StudentDTO();
tony.setEmailAddress("tony.tester#gmail.com");
tony.setName("Tony Tester");
tony.setPurchasedPackage("master");
StudentDTO nick = new StudentDTO();
nick.setEmailAddress("nick.newbie#gmail.com");
nick.setName("Nick Newbie");
nick.setPurchasedPackage("starter");
StudentDTO ian = new StudentDTO();
ian.setEmailAddress("ian.intermediate#gmail.com");
ian.setName("Ian Intermediate");
ian.setPurchasedPackage("intermediate");
studentData = Collections.unmodifiableList(Arrays.asList(tony, nick, ian));
nextStudentIndex = 0;
}
#Override
public StudentDTO read() throws Exception {
StudentDTO nextStudent = null;
if (nextStudentIndex < studentData.size()) {
nextStudent = studentData.get(nextStudentIndex);
nextStudentIndex++;
}
return nextStudent;
}
}
As you can see here we can iterate on a list by it's position (index), so when we call next time the method read() we garantie that we get the next elment.
But in my case the is no notion of index, as HashMap has no concept of position so there is no way to get an object by position.
haw can update this code to work with my case:
public class InMemoryMouvementReader implements ItemReader<MouvementFileRow> {
#Autowired
private MouvementToMap mvts;
#Override
public MouvementFileRow read() throws Exception {
MouvementFileRow nextMouvement = null;
// the Map
// public Map<Long, MouvementFileRow> getMouvmentFileRowMap() {
// return mouvmentFileRowMap;
// }
mvts.getMouvmentFileRowMap()
return nextMouvement;
}
}
do i need to change the hashMap to LinkedHashMap instead or to convert map to List ?
There are no indexes like 0, 1, ... n but you can use the keys in an specific order (e.g. alphabetic sort). Another approach is to get a Iterator object by calling yourHashMap.keySet().iterator() and use that object as class-attribute instead of the nextStudentIndex-attribute. Then use a code snippet like:
if (yourIterator.hasNext()) return yourHashMap.get(youtIterator.next());
else return null;
If you don't want to use any kind of index in your implementation, then read(idx) can be written in the loop, where read() is going to be called idx times.
First of all my objects:
public class Group {
private final ObservableList<IDevice> sourceList;
private final ObservableList<IDevice> destinationList;
private final ObservableList<Mapping> mappingList;
...}
public class Mapping {
private final IDevice source;
private final IDevice destination;
private final MappingMode mode;
public final StringProperty sourceName = new SimpleStringProperty();
public final StringProperty destinationName = new SimpleStringProperty();
public final StringProperty modeName = new SimpleStringProperty();
...}
Basically a group contains two lists of IDevices which can either be source or destination and a mapping list that contains one of them and one of two modes (enum).
The IDevice lists are displayed in an own listview with a table between them, representing the mapping (containing one column from the first, one from the second list and the mode column).
I have added them via setItems, this is the CellFactory for the ListViews
private Callback<ListView<IDevice>, ListCell<IDevice>> getFullNameDisplay() {
return new Callback<ListView<IDevice>, ListCell<IDevice>>() {
#Override
public ListCell<IDevice> call(ListView<IDevice> p) {
ListCell<IDevice> cell = new ListCell<IDevice>() {
#Override
protected void updateItem(IDevice t, boolean bln) {
super.updateItem(t, bln);
if (t != null) {
setText(t.getFullName());
}
else
setText("");
}
};
return cell;
}
};
}
The columns are set like this:
sourceColumn.setCellValueFactory(cellData -> cellData.getValue().sourceName);
destinationColumn.setCellValueFactory(cellData -> cellData.getValue().destinationName);
modeColumn.setCellValueFactory(cellData -> cellData.getValue().modeName);
I added two buttons for each listview to add and remove new items.
Of course if I remove a source or destination device, I want all of its mappings removed, so I added a ListChangeListener to the two lists:
private ListChangeListener<IDevice> getDeviceChangeListener() {
return (javafx.collections.ListChangeListener.Change<? extends IDevice> c) -> {
while (c.next()) {
if (c.wasRemoved()) {
c.getRemoved().stream().forEach((d) -> {
mappingList.stream().filter((map) -> (map.getSource().equals(d) || map.getDestination().equals(d))).forEach((map) -> {
mappingList.remove(map);
});
});
}
}
};
}
This also does what I intended it to do (and also all refactorings I tried did), but i cant get why this invokes (most of the time) a ConcurrentModificationException as I have not yet used any threading in my application. It seems as it doesnt trigger each time, which I understand can be lucky scheduling if I would be using threads.. The result is correct though
Someone any clue?
Thanks in advance
You cannot modify a collection while iterating through it, unless the modification is done via the iterator. In Java 8, the Collection class introduced a removeIf(...) method which helps in this use case:
private ListChangeListener<IDevice> getDeviceChangeListener() {
return (javafx.collections.ListChangeListener.Change<? extends IDevice> c) -> {
while (c.next()) {
if (c.wasRemoved()) {
c.getRemoved().forEach(d ->
mappingList.removeIf(map -> map.getDestination().equals(d)
|| map.getSource().equals(d)));
}
}
};
}
In the same loop if you are trying to iterate over the same collection and trying to modify the same collection, Java throws this concurrency exception.
If you want to modify the collection, please mantain a different collection for addition or modification. Once it comes out of the loop, call Collection.addAll() or Collection.removeAll() interface.
suppose I have defined a List as
private BlockingQueue<MyDelayed> DelayedIds = new DelayQueue<>();
class MyDelayed is like:
private class MyDelayed implements Delayed {
private String myId;
private Long creationTime;
MyDelayed (String myId) {
this.myId= myId;
this.creationTime = System.currentTimeMillis();
}
String getMyId() {
return this.myId;
}
#Override
public long getDelay(TimeUnit unit) {
//TODO
}
#Override
public int compareTo(Delayed o) {
//TODO
}
}
Now suppose that I want to add an Object of class MyDelayed in DelayedIds list.
I can do it by using add function.
But If I want to add obbject in list only if list does not contain an object of class MyDelayed which has the same myId attribute which I am trying to insert.
Obviously DelayedIds .contains(new MyDelayed(myId)) will not work.
Is there any easy way to check this thing ?
Am I missing something ?
You could write something like this and compare every element in the list to see if it contains your id. If at any point you find a matching one you return true, if the loop finished having found none it returns false.
public boolean contains(String id){
for (MyDelayed md : DelayedIds){
if(md.getMyId().equals(id)){
return true;
}
}
return false;
}
Now to check before adding you would do something like:
if(!contains(myNewObject.getMyId())){
DelayedIds.add(myNewObject)
}
Also, I'd suggest that you rename DelayedIds to delayedIds in order to follow coding standards (see Variables).
I have a Java application and I want to implement an Undo/Redo option. the value that I want to stock and that I want to be able to recover is an integer.
My Class Model implements the interface StateEditable and I have to redefine the 2 functions restoreState(Hashtable<?, ?> state) and storeState(Hashtable<Object, Object> state) but I don't know what to put on them. It will be really great if somebody can help me to do that.
These are the first lines of my Model class, the value that I want to do an undo/redo on it is value
public class Model extends Observable implements StateEditable
{
private int value = 5;
private UndoManager undoRedo = new UndoManager();
final UndoableEditListener editListener = new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
undoRedo.addEdit(evt.getEdit());
}
};
#Override
public void restoreState(Hashtable<?, ?> state)
{
}
#Override
public void storeState(Hashtable<Object, Object> state)
{
}
}
From looking through an example of StateEditable, it would appear that in your storeState method, you need to populate the Hashtable that is passed in. Similarly, you assign state in your restoreState from the Hashtable that is passed in. You will need to define a key for the value in the Hashtable. With that in mind, I suggest that you add
private final String KEY = "myKey";
to the top of your file, and then fill out the two methods like so:
#Override
public void restoreState(Hashtable<?, ?> state)
{
Object val = state.get(KEY);
if( val instanceof Integer ) //performs the null test for us.
{
value = val;
}
}
#Override
public void storeState(Hashtable<Object, Object> state)
{
state.put(KEY, value);
}
I know about SortedSet, but in my case I need something that implements List, and not Set. So is there an implementation out there, in the API or elsewhere?
It shouldn't be hard to implement myself, but I figured why not ask people here first?
There's no Java collection in the standard library to do this. LinkedHashSet<E> preserves ordering similarly to a List, though, so if you wrap your set in a List when you want to use it as a List you'll get the semantics you want.
Alternatively, the Commons Collections (or commons-collections4, for the generic version) has a List which does what you want already: SetUniqueList / SetUniqueList<E>.
Here is what I did and it works.
Assuming I have an ArrayList to work with the first thing I did was created a new LinkedHashSet.
LinkedHashSet<E> hashSet = new LinkedHashSet<E>()
Then I attempt to add my new element to the LinkedHashSet. The add method does not alter the LinkedHasSet and returns false if the new element is a duplicate. So this becomes a condition I can test before adding to the ArrayList.
if (hashSet.add(E)) arrayList.add(E);
This is a simple and elegant way to prevent duplicates from being added to an array list. If you want you can encapsulate it in and override of the add method in a class that extends the ArrayList. Just remember to deal with addAll by looping through the elements and calling the add method.
So here's what I did eventually. I hope this helps someone else.
class NoDuplicatesList<E> extends LinkedList<E> {
#Override
public boolean add(E e) {
if (this.contains(e)) {
return false;
}
else {
return super.add(e);
}
}
#Override
public boolean addAll(Collection<? extends E> collection) {
Collection<E> copy = new LinkedList<E>(collection);
copy.removeAll(this);
return super.addAll(copy);
}
#Override
public boolean addAll(int index, Collection<? extends E> collection) {
Collection<E> copy = new LinkedList<E>(collection);
copy.removeAll(this);
return super.addAll(index, copy);
}
#Override
public void add(int index, E element) {
if (this.contains(element)) {
return;
}
else {
super.add(index, element);
}
}
}
Why not encapsulate a set with a list, sort like:
new ArrayList( new LinkedHashSet() )
This leaves the other implementation for someone who is a real master of Collections ;-)
You should seriously consider dhiller's answer:
Instead of worrying about adding your objects to a duplicate-less List, add them to a Set (any implementation), which will by nature filter out the duplicates.
When you need to call the method that requires a List, wrap it in a new ArrayList(set) (or a new LinkedList(set), whatever).
I think that the solution you posted with the NoDuplicatesList has some issues, mostly with the contains() method, plus your class does not handle checking for duplicates in the Collection passed to your addAll() method.
I needed something like that, so I went to the commons collections and used the SetUniqueList, but when I ran some performance test, I found that it seems not optimized comparing to the case if I want to use a Set and obtain an Array using the Set.toArray() method.
The SetUniqueTest took 20:1 time to fill and then traverse 100,000 Strings comparing to the other implementation, which is a big deal difference.
So, if you worry about the performance, I recommend you to use the Set and Get an Array instead of using the SetUniqueList, unless you really need the logic of the SetUniqueList, then you'll need to check other solutions...
Testing code main method:
public static void main(String[] args) {
SetUniqueList pq = SetUniqueList.decorate(new ArrayList());
Set s = new TreeSet();
long t1 = 0L;
long t2 = 0L;
String t;
t1 = System.nanoTime();
for (int i = 0; i < 200000; i++) {
pq.add("a" + Math.random());
}
while (!pq.isEmpty()) {
t = (String) pq.remove(0);
}
t1 = System.nanoTime() - t1;
t2 = System.nanoTime();
for (int i = 0; i < 200000; i++) {
s.add("a" + Math.random());
}
s.clear();
String[] d = (String[]) s.toArray(new String[0]);
s.clear();
for (int i = 0; i < d.length; i++) {
t = d[i];
}
t2 = System.nanoTime() - t2;
System.out.println((double)t1/1000/1000/1000); //seconds
System.out.println((double)t2/1000/1000/1000); //seconds
System.out.println(((double) t1) / t2); //comparing results
}
Regards,
Mohammed Sleem
My lastest implementation: https://github.com/marcolopes/dma/blob/master/org.dma.java/src/org/dma/java/util/UniqueArrayList.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
* Extends <tt>ArrayList</tt> and guarantees no duplicate elements
*/
public class UniqueArrayList<T> extends ArrayList<T> {
private static final long serialVersionUID = 1L;
public UniqueArrayList(int initialCapacity) {
super(initialCapacity);
}
public UniqueArrayList() {
super();
}
public UniqueArrayList(T[] array) {
this(Arrays.asList(array));
}
public UniqueArrayList(Collection<? extends T> col) {
addAll(col);
}
#Override
public void add(int index, T e) {
if (!contains(e)) super.add(index, e);
}
#Override
public boolean add(T e) {
return contains(e) ? false : super.add(e);
}
#Override
public boolean addAll(Collection<? extends T> col) {
Collection set=new LinkedHashSet(this);
set.addAll(col);
clear();
return super.addAll(set);
}
#Override
public boolean addAll(int index, Collection<? extends T> col) {
Collection set=new LinkedHashSet(subList(0, index));
set.addAll(col);
set.addAll(subList(index, size()));
clear();
return super.addAll(set);
}
#Override
public T set(int index, T e) {
return contains(e) ? null : super.set(index, e);
}
/** Ensures element.equals(o) */
#Override
public int indexOf(Object o) {
int index=0;
for(T element: this){
if (element.equals(o)) return index;
index++;
}return -1;
}
}
Off the top of my head, lists allow duplicates. You could quickly implement a UniqueArrayList and override all the add / insert functions to check for contains() before you call the inherited methods. For personal use, you could only implement the add method you use, and override the others to throw an exception in case future programmers try to use the list in a different manner.
The documentation for collection interfaces says:
Set — a collection that cannot contain duplicate elements.
List — an ordered collection (sometimes called a sequence). Lists can contain duplicate elements.
So if you don't want duplicates, you probably shouldn't use a list.
in add method, why not using HashSet.add() to check duplicates instead of HashSet.consist().
HashSet.add() will return true if no duplicate and false otherwise.
What about this?
Just check the list before adding with a contains for an already existing object
while (searchResult != null && searchResult.hasMore()) {
SearchResult nextElement = searchResult.nextElement();
Attributes attributes = nextElement.getAttributes();
String stringName = getAttributeStringValue(attributes, SearchAttribute.*attributeName*);
if(!List.contains(stringName)){
List.add(stringName);
}
}
I just made my own UniqueList in my own little library like this:
package com.bprog.collections;//my own little set of useful utilities and classes
import java.util.HashSet;
import java.util.ArrayList;
import java.util.List;
/**
*
* #author Jonathan
*/
public class UniqueList {
private HashSet masterSet = new HashSet();
private ArrayList growableUniques;
private Object[] returnable;
public UniqueList() {
growableUniques = new ArrayList();
}
public UniqueList(int size) {
growableUniques = new ArrayList(size);
}
public void add(Object thing) {
if (!masterSet.contains(thing)) {
masterSet.add(thing);
growableUniques.add(thing);
}
}
/**
* Casts to an ArrayList of unique values
* #return
*/
public List getList(){
return growableUniques;
}
public Object get(int index) {
return growableUniques.get(index);
}
public Object[] toObjectArray() {
int size = growableUniques.size();
returnable = new Object[size];
for (int i = 0; i < size; i++) {
returnable[i] = growableUniques.get(i);
}
return returnable;
}
}
I have a TestCollections class that looks like this:
package com.bprog.collections;
import com.bprog.out.Out;
/**
*
* #author Jonathan
*/
public class TestCollections {
public static void main(String[] args){
UniqueList ul = new UniqueList();
ul.add("Test");
ul.add("Test");
ul.add("Not a copy");
ul.add("Test");
//should only contain two things
Object[] content = ul.toObjectArray();
Out.pl("Array Content",content);
}
}
Works fine. All it does is it adds to a set if it does not have it already and there's an Arraylist that is returnable, as well as an object array.