Java | Adding items to List<?> - java

I googled around and I couldn't really understand how to do this. I'm trying to add items to a list like this: List<?>. My code looks something like this:
public class Test {
private List<?> list;
public Test(List<?> useThisList) {
this.list = useThisList;
}
public void add(Object add) {
this.list.add(add); // this won't compile
}
}
However, as commented, that code won't compile. I've tried to change it to something like:
public void add(? add) {
this.list.add(add);
}
But that won't compile for more obvious reasons.
Does anyone know what I need to change this to to make it function properly? Thanks in advance!
By the way, when it does work, you should be able to do this:
List<String> list = new ArrayList<String>();
new Test(list).add("hello");

Make your Test class generic
public class Test<E> {
private List<E> list;
public Test(List<E> useThisList) {
this.list = useThisList;
}
public void add(E add) {
this.list.add(add); // this will compile
}
}
Instantiate your test class like this
Test<String> t = new Test<String>(new ArrayList<String>());
t.add("Something");

Related

How to refer to generic paramenter's own parameters, such as T in T2<T>?

Consider following interface:
class SomeParamClass<T> {
public T getT() {return null;}
}
class GetThing<T, TSomeImpl extends SomeParamClass<T>> {
TSomeImpl thingcreator;
GetThing(TSomeImpl thingcreator) {
this.thingcreator = thingcreator;
}
T getThing() {
return thingcreator.get(offset);
}
TSomeImpl getOrigClass() {
return thingcreator;
}
}
This is just an example of a problem that I encountered few times already.
In this example, type T is directly bound to parameter TSomeImpl. If you create it like this:
new GetThing<String,TSomeImpl<String>>(new TSomeImpl<String>())
The parameter String is repeated unnecessarily. It is redundant, but Java seems to require it in this case.
Is there a way to use generic parameters inner parameter as a type?
I made up this syntax, is there a syntax that actually works for this?
// Pseudocode on refering to generic parameter's parameters
class GetThing<TSomeImpl extends SomeParamClass<T>, TSomeImpl::<T>> {
TSomeImpl thingcreator;
GetThing(TSomeImpl thingcreator) {
this.thingcreator = thingcreator;
}
TSomeImpl::<T> getThing() {
return thingcreator.get(offset);
}
TSomeImpl getOrigClass() {
return thingcreator;
}
}
That would be than used just as:
GetThing<TSomeImpl<String>>
No other parameters are necessary.
To clarify: How can I re-write the original class so that it only has one generic argument, List<T> and the T argument is inferred, since it is unambiguously known from List<T>.
what about this
interface SomeType<T> {
T getT();
}
class SomeParamClass<T> implements SomeType<T> {
public T getT() {return null;}
}
class GetThing<T> {
SomeType<T> thingcreator;
GetThing(SomeType<T> thingcreator) {
this.thingcreator = thingcreator;
}
T getThing() {
return thingcreator.getT();
}
SomeType<T> getOrigClass() {
return thingcreator;
}
}
you can use it like this
new GetThing<String>(new SomeParamClass<>());
The problem is that you're trying to use TList as some kind of alias. That's not what generics are for.
Generic type parameters are just that: parameters. There's no way to hide a parameter. They must be explicit.
What's wrong with this? Why doesn't it satisfy your requirements?
class GetListEntry<T>
{
List<T> list;
GetListEntry(List<T> list) {
this.list = list;
}
T getValueAt(int offset) {
return list.get(offset);
}
}
Maybe I do not understand the problem but what is TList for? Looks like a redundant definition. Wouldn't something like this work:
public class ListOfSomething<T> {
private List<T> things;
public ListOfSomething(List<T> things) {
super();
this.things = things;
}
T getValueAt(int offset) {
return this.things.get(offset);
}
}
I would referr to Michaels answer. There does not seem to be an apparent reason for you to mask your list like that. However, if you really want to do it this way, I belive you can do it by just leaving out the generic parameters in your variable declaration. The only place you need to specify this, is the parameters of the constructor. So, just using
GetListEntry test = new GetListEntry(new ArrayList<String>());
should work fine.
You can try my test code on this java online compiler. Thats where I tried it and it works fine.
import java.util.List;
import java.util.ArrayList;
public class MyClass {
public static void main(String args[]) {
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("1");
stringList.add("2");
stringList.add("3");
GetListEntry test = new GetListEntry(stringList);
for(int i = 0; i <= 2; i++)
System.out.println(test.getValueAt(i));
}
static class GetListEntry<T, TList extends List<T>> {
TList list;
GetListEntry(TList list) {
this.list = list;
}
T getValueAt(int offset) {
return list.get(offset);
}
}
}
As you said, the information is redundant. So, the needed information is taken from where its already mentioned. Namely, the ArrayList's generic Type.

jList not displaying data in specific case

In my program, I have a jList and I can add, delete, modify items in this Jlist.
My problem is, if I click on my add button before selecting an item in my jList, the items inside the jList disapear. (only in apeareance because they are actually still in the jList)
If, before that, I select an item in my list, then everything is working fine. So my guess would be that the "valueChanged()" method from my listener is doing something that I don't do myself.
Here is my list initialisation, which I call at the start of the program:
public final void initList() {
jListPaiement.setModel(new MyListModel(ls.getDb().getListePaiements()));
final DecimalFormat df = new DecimalFormat("###.##");
jListPaiement.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent lse) {
MoyenPaiement mp = (MoyenPaiement) ((MyListModel) jListPaiement.getModel()).getElementAt(jListPaiement.getSelectedIndex());
jTextFieldFF.setText(df.format(mp.getFraisf()));
jTextFieldFV.setText(df.format(mp.getFraisv() * 100));
jTextFieldNomP.setText(mp.getNom());
jTextFieldFF.setVisible(true);
jTextFieldFV.setVisible(true);
jTextFieldNomP.setVisible(true);
jLabel1.setVisible(true);
jLabel6.setVisible(true);
jLabel7.setVisible(true);
jLabel8.setVisible(true);
jLabel11.setVisible(true);
jButtonSaveP.setVisible(true);
}
});
Here is the code from the add button:
private void jButtonAddPActionPerformed(java.awt.event.ActionEvent evt) {
MoyenPaiement mp = new MoyenPaiement("Nouveau", 0, 0);
((MyListModel) jListPaiement.getModel()).addElement(mp);
jListPaiement.setSelectedValue(mp, true);
jListPaiement.repaint();
}
MyListModel code:
public class MyListModel extends AbstractListModel {
ArrayList list;
public MyListModel(ArrayList list) {
this.list = list;
}
#Override
public int getSize() {
return list.size();
}
#Override
public Object getElementAt(int i) {
return list.get(i);
}
public void addElement(Object o){
list.add(o);
}
public void deleteElement(Object o){
list.remove(o);
}
public void setElement(int i,Object o){
list.set(i, o);
}
public ArrayList getList() {
return list;
}
public void setList(ArrayList list) {
this.list = list;
}
}
Any help will be greatly appreciated.
Thanks
Edit: After further research, the problem is when I add item to my model.
It comes exactly on the line:
((MyListModel) jListPaiement.getModel()).addElement(mp);
Even if I add a simple string such as:
((MyListModel) jListPaiement.getModel()).addElement("String");
The problem still occurs.
Look in detail what happens on this line and if you initialize jListPaiement correctly with the right data.
jListPaiement.setModel(new MyListModel(ls.getDb().getListePaiements()));
Seems like on this line setSelectedValue() can't find the element mp
jListPaiement.setSelectedValue(mp, true);
I finally found a solution.
Rather than using my own List Model, I used DefaultListModel and everything works fine. It's been long time since i worked on this project and I don't remember why i chose to make my own list model class.
Even tough it works now, I still don't understand what was missing in my own class (MyListModel) that made it not working..

custom arraylist with notification for delete and add

I want to detect when adding some items to the array list or when removing some item from it. Actually I have some code like below:
public class myClass {
MyCustomArrayList<MyObject> al;
public void method1() {
al.add(myObject);
// Do other works
al.remove(myObject)
// Do other works
}
private void DoByEachAdd() {
//I want array list call this method by adding each item to it.
// It should be in this class because it is doing some works
// related to this class. for example changing some private variables
}
private void DoByEachRemove() {
// I want array list call this method by adding each item to it.
// It should be in this class too.
}
}
I know that array list has not the ability for having listener or some kind of notifications or events and if I want to detect add should have a custom array list. something like below class:
class MyArrayList<T> {
private ArrayList<T> list;
public MyList(){
list = new ArrayList<>();
...
}
public void add(T t) {
list.add(t) {
//do other things you want to do when items are added
}
public T remove(T t) {
list.remove(t);
//do other things you want to do when items are removed
}
(I get it from here)
So the question is that: how can I inform the object of MyArrayList (al) that call DoByEachAdd and DoByEachRemove methods when the remove and add method fired. Does some body have any ideas?
First, follow naming convention. Second, the three class names you used for the same class, MyList, MyArrayList and MyCustomArrayList will confuse people. As for your question, you would have to have an instance field inside MyArrayList of type myClass (unless you want to refactor DoByEachAdd and DoByEachRemove to be static). This can be done by adding it as a constructor parameter, e.g.
// inside MyArrayList
private ArrayList<T> list;
private final myClass instance;
public MyArrayList(myClass instance) { // <-- NOT MyList
list = new ArrayList();
this.myClass = myClass;
}
Also, I question your approach. Other classes with instances of MyArrayList can only use the add and remove methods of ArrayList. If you want to save a lot of bother and have all methods visible, either declare list as public final or make MyArrayList a subclass of ArrayList, e.g.
public class MyArrayList<T> extends ArrayList<T> {
private final myClass instance;
public MyArrayList(myClass instance) { // <-- NOT MyList
list = new ArrayList();
this.myClass = myClass;
}
#Override
public boolean add(T t) {
boolean returnThis = super.add(t);
// do some stuff
instance.DoByEachAdd();
return returnThis;
}
#Override
public boolean remove(T t) {
boolean returnThis = super.remove(t);
// do some stuff
instance.DoByEachRemove();
return returnThis;
}
}
If you insist on being able to return a T from remove, declare another method:
public T removeT(T t) {
remove(t);
// do some stuff
return someT;
}
you need to give access to your myClass to MyArrayList
class MyArrayList<T> {
private ArrayList<T> list;
private myClass theClass;
public MyList(myClass theClass){
list = new ArrayList<>();
this.theClass = theClass;
...
}
public void add(T t) {
list.add(t) {
//do other things you want to do when items are added
theClass.DoByEachAdd();
}
public T remove(T t) {
list.remove(t);
//do other things you want to do when items are removed
theClass.DoByEachRemove
}
and in your myClass give the object to your list
public class myClass {
MyCustomArrayList<MyObject> al;
public myClass(){
al = new MyCustomArrayList<MyObject>(this);
}
public void method1() {
al.add(myObject);
// Do other works
al.remove(myObject)
// Do other works
}
public void DoByEachAdd() {
//I want array list call this method by adding each item to it.
// It should be in this class because it is doing some works
// related to this class. for example changing some private variables
}
public void DoByEachRemove() {
// I want array list call this method by adding each item to it.
// It should be in this class too.
}
}

How can I call a constructor after statements?

I have this calss KeywordFilter. I want the constrcutor that accepts a keyword to create a List, add the keyword to the list and then call the constructor with the list parameter. How can I do that? because as I know, calling the constructor should be the first call.
public class KeywordFilter implements Filter {
private List<String> filteringKeywords;
public KeywordFilter(List<String> filteringKeywords) {
this.filteringKeywords = filteringKeywords;
}
public KeywordFilter(String keyword) {
List<String> filteringKeywords = new ArrayList<String>();
filteringKeywords.add(keyword);
this(filteringKeywords);//This makes a compilation error
}
}
Create your list directly :
public KeywordFilter(String keyword) {
this(new ArrayList<String>(Arrays.asList(keyword)));
}
In general, you can put the code that constructs the list in a separate function (preferably, but not necessarily, static):
private static List<String> makeFilterKeywords(String keyword) {
List<String> filteringKeywords = new ArrayList<String>();
filteringKeywords.add(keyword);
return filteringKeywords;
}
public KeywordFilter(String keyword) {
this(makeFilterKeywords(keyword));
}
This should help
public KeywordFilter(String keyword) {
this(Collections.singletonList(keyword));
}
public KeywordFilter(List<String> filteringKeywords) {
this.filteringKeywords = filteringKeywords;
}
public KeywordFilter(String keyword) {
this(((List<String>)Arrays.asList(keyword));
}
The simplest and shorten solution
public KeywordFilter(String keyword) {
this(Arrays.asList(keyword));
}
But this returns a fixed-size list backed by the specified array, without add() or remove() support.
This is applicable also to varargs
public KeywordFilter(String... keywords) {
this(Arrays.asList(keywords));
}
You can create the ArrayList with the KeyWord and then have another method append the new list to existing list (which you have created with only the keyword in the constructor).
Something like this:
public class KeywordFilter implements Filter {
private List<String> filteringKeywords;
public KeywordFilter(String keyword) { //Consctructor
filteringKeywords = new ArrayList<String>();
filteringKeywords.add(keyword);
}
public void appendList(List<String> filteringKeywords) { //new method
filteringKeywords.addAll(filteringKeywords);
}
}

Using generics to refactor

I am used to use generics in typed collections, but I never actually used them to develop something.
I have several classes like this:
public class LogInfoWsClient extends GenericWsClient {
public void sendLogInfo(List<LogInfo> logInfoList) {
WebResource ws = super.getWebResource("/services/logInfo");
try {
String response = ws.accept(MediaType.TEXT_HTML).type(MediaType.APPLICATION_XML).put(String.class, new GenericEntity<List<LogInfo>>(logInfoList) {
});
}
}
Where the only thing changing between one and another is the service String ("/services/info"), and the type of the list (LogInfo in this case)
I have refactored a couple of methods to a GenericWsClient class, but my objective would be to have something I can use like this:
List<LogInfo> myList = database.getList();
SuperGenericClient<List<LogInfo>> superClient = new SuperGenericClient<List<LogInfo>>();
superClient.send(myList,"/services/logInfo");
But I cannot figure out how to do it, or even if its possible. Would it be possible?
Yes it is possible infact if you look at java.util.collection package for example you will find all classes to be parameterzid.
So your class will be something like this
public SuperGenericClient<E> {
public E getSomething() {
return E;
}
}
Then to use it you will have
SuperGenericClient<String> myGenericClient = new SuperGenericClient<String>();
String something = myGenericClient.getSomething();
Extending your example itself your code will look like this:
public class SuperGenericClient<E> extends GenericWsClient {
public void send(List<E> entityList, String service) {
WebResource ws = super.getWebResource(service);
try {
String response = ws.accept(MediaType.TEXT_HTML).type(MediaType.APPLICATION_XML).put(String.class, new GenericEntity<E>(entityList) {
});
}
}
}
public class GenericEntity<E> {
public GenericEntity(List<E> list){
}
}
You must read this for a very good understanding of Generics.
You could write your class like the one below - you can apply the same idea to GenericEntity.
public class SuperGenericClient<T> extends GenericWsClient {
public void send(List<T> list, String service) {
WebResource ws = super.getWebResource(service);
try {
String response = ws.accept(MediaType.TEXT_HTML).type(MediaType.APPLICATION_XML).put(String.class, new GenericEntity<T>(list) {
});
}
}
}
You can then call it like that:
List<LogInfo> myList = database.getList();
SuperGenericClient<LogInfo> superClient = new SuperGenericClient<LogInfo>();
superClient.send(myList,"/services/logInfo");
Declare your class like this:
public class LogThing<T> {
public void sendLogInfo(List<T> list) {
// do thing!
}
}
And when you use it, do so like this:
List<LogInfo> myList = db.getList();
LogThing<LogInfo> superClient = new LogThing<LogInfo>();
superClient.sendLogInfo(myList);

Categories

Resources