custom arraylist with notification for delete and add - java

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.
}
}

Related

How can I add a value to an ArrayList from an inner method?

I am currently trying to add a value to an ArrayList object from a method inside of another class.
Here is the class I have created for the ArrayList Object:
public class ArrayClass {
public static ArrayList<String> array = new ArrayList<>();
public static void add_val(String s){
array.add(s);
}
public static int get_size(){
return array.size();
}
public static String get_val(int i){
return array.get(i);
}
}
And the other class where I attempt to edit the ArrayList object:
ArrayClass fill = new ArrayClass();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_explore);
Response.Listener<String> responseListener4 = new Response.Listener<String>(){
#Override
public void onResponse(String response) {
try {
JSONObject jsonResponse4 = new JSONObject(response);
boolean success = jsonResponse4.getBoolean("success");
if (success){
int l;
String filled;
int length4 = jsonResponse4.length();
for (l=0;l<length4;l++){
filled = jsonResponse4.getString(l+"");
fill.add_val(filled);
}
}else{
AlertDialog.Builder builder = new AlertDialog.Builder(ExploreActivity.this);
builder.setMessage("Could not retrieve restaurant tables filled")
.setNegativeButton("Retry", null)
.create()
.show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
};
FilledRequest filledRequest = new FilledRequest(responseListener4);
RequestQueue queue4 = Volley.newRequestQueue(ExploreActivity.this);
queue4.add(filledRequest);
If you look in the onResponse method, you can see the attempt to add a value from the jsonResponse into the ArrayClass object. However, when I launch my app, it does not add the value into the object. I'm used to python global variables and not having to deal with the semantics of java, so if you could shed some light on what changes need to be made, I would greatly appreciate it.
Apart from other given answers/solutions to the issue you are facing, let me share a best and optimized way to implement JSON parsing in Android.
I would suggest you to check GSON or Jackson libraries which provides Java serialization/deserialization that can convert Java Objects into JSON and back.
There are some benefits it does provide, one of the main benefits is you do not need to implement parsing manually and less chances of mistakes in implementing parsing, like you may make a mistake in mentioning key "Success" or "success" or any such silly mistakes!
Firstly, since your variable is static, and the methods are static too, you don't have to instantiate the object. You could do something like this:
ArrayClass.add_val("Hello");
But if you want to instantiate then you can do this:
public class ArrayClass {
private ArrayList<String> array;
public ArrayClass() {
array = new ArrayList<>();
}
public void add_val(String s){
array.add(s);
}
public int get_size(){
return array.size();
}
public String get_val(int i){
return array.get(i);
}
}
To make sure the values are filled in, you can check the array size like this:
for (l=0;l<length4;l++){
filled = jsonResponse4.getString(l+"");
fill.add_val(filled);
}
Log.d("TEST", String.valueOf(fill.get_size());
Remove all cases of the static keyword in ArrayClass. Static methods are class level methods, ie. are called on the class itself, rather than an instance of the class.
You can also try this, for ArrayList:
First do some changes in your ArrayClass. Use get And Set method to access your array.
public class ArrayClass {
private ArrayList<String> array = new ArrayList<>();
public ArrayList<String> getArray() {
return array;
}
public void setArray(ArrayList<String> array) {
this.array = array;
}
}
And your other class where you attempt to edit the ArrayList use getArray And SetArray method and some predefined method of ArrayList like this:
Store the data in ArrayList:
for (l=0;l<length4;l++){
filled = jsonResponse4.getString(l+"");
fill.getArray().add(filled);
}
Get Size of ArrayList:
fill.getArray().size();
And also you can store an another ArrayList like
ArrayList<String> tempArrayList = new ArrayList<String>();
tempArrayList.add("string 1");
tempArrayList.add("string 2");
tempArrayList.add("string 3");
tempArrayList.add("string 4");
fill.setArray(tempArrayList)

Java | Adding items to List<?>

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");

Class exporting iterators on two collections

Consider the case where a class contains two collections. Is it possible to provide iterators over both collections in a way that callers can use to iterate over?
My simple example:
public class Bar {
public static class Beer { /* ... */ }
public static class Wine { /* ... */ }
private Set<Beer> beers = new HashSet<Beer>();
private Set<Wine> wines = new HashSet<Wine>();
public Iterator<Beer> beerIterator() { return beers.iterator(); }
public Iterator<Wine> wineIterator() { return wines.iterator(); }
}
So far, so good. We can declare the methods that return the iterators, but the way I'm trying to do it, the caller can't use the iterator to, well, iterate.
void caller(Bar bar) {
for (Beer beer: bar.beerIterator()) { // <-- Compilation error: Can only iterate over an array or an instance of java.lang.Iterable
}
}
Any suggestions?
If the point in returning iterators is to protect your collections from changes while giving client ability to use foreach loops, then the most clear way will be to use Collections.unmodifiableSet wrapper. You can return it as Iterable interface to hide the implementation even further.
public static class Bar {
public static class Beer { /* ... */ }
public static class Wine { /* ... */ }
private Set<Beer> beers = new HashSet<Beer>();
private Set<Wine> wines = new HashSet<Wine>();
public Iterable<Beer> beerIterable() { return Collections.unmodifiableSet(beers); }
public Iterable<Wine> wineIterable() { return Collections.unmodifiableSet(wines); }
}
public static void main(String[] args) {
for (Bar.Beer beer : new Bar().beerIterable()) {
}
}
This approach is better than one suggested by #Tim Biegeleisen, because it protects your collection from being changed from outside. When you return .iterator of your original collection, client is still able to modify original collection by calling remove() method. Wrapping in unmodifiableSet prevents that.
However, be aware that client still can modify returned instances of Beer and Wine during the iteration, if they are mutable. If you want to be fully protected from changes, you need to make deep defensive copies of your collections before returning them to client.
The trick is to define 2 inner classes inside Bar which return custom iterators for beer and wine:
public class Bar {
public static class Beer { /* ... */ }
public static class Wine { /* ... */ }
private Set<Beer> beers = new HashSet<Beer>();
private Set<Wine> wines = new HashSet<Wine>();
private class Beers implements Iterable<Beer> {
#Override
public Iterator<Beer> iterator() {
return beers.iterator();
}
}
private class Wines implements Iterable<Wine> {
#Override
public Iterator<Wine> iterator() {
return wines.iterator();
}
}
public Beers beers() {
return new Beers();
}
public Wines wines() {
return new Wines();
}
}
You can use the custom iterators like this:
Bar bar = new Bar();
// add some beers and wines here
for (Beer beer : bar.beers()) {
System.out.println("Found another beer: " + beer);
}
for (Wine wine : bar.wines()) {
System.out.println("Found another wine: " + wine);
}

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);
}
}

generic type that extends interface, my variable returns null unless i cast it to a specific class

I have a class that i'm uses a generic Type that extends the interface zwave
everything is fine until i try to access a zwave variable for some reason the rm.keyword gives a "NullPointerException". if I cast it to the class scene it works, but that is not what I want
public <T extends zwave> T Find(List<T> Zwave,List<List<String>> listofinputstrings)
{
for(List<String> lst: listofinputstrings)
{
for(String str: lst)
{
for (T rm: Zwave)
{
//*** problem is here
//rm.keyword is always gives a NullPointerException unless i cast it to a class
if (rm.keyword.equals( str.toLowerCase()))
{
return rm;
}
}
}
}
return null;
}
//here is the interface
interface zwave
{
public String keyword="";
public String zwaveID="";
}
//here is a class that implements the interface
public class Scene implements zwave
{
String name;
String keyword;
String zwaveID;
public Scene(String Name,String Keyword,String ZwaveID)
{
name= Name;
zwaveID= ZwaveID;
keyword = Keyword;
}
}
edit
Working code
//search class
public <T extends searchable> T Find(List<T> searchableclasses, List<List<String>> listofinputstrings)
{
for(List<String> lst: listofinputstrings)
{
for(String str: lst)
{
for (T searchable: searchableclasses)
{
for(String key: searchable.GetKeywords())
{
if ( key.equals(str.toLowerCase()))
{
return searchable;
}
}
}
}
}
return null;
}
//abstract class
abstract class searchable
{
String[] keywords; //using array so i can use java's param ability
public List<String> GetKeywords()
{
return new ArrayList(Arrays.asList(keywords));
}
}
//actual class
public class Scene extends searchable
{
String name;
String zwaveID;
public Scene(String Name,String ZwaveID,String... Keywords)
{
name= Name;
zwaveID= ZwaveID;
keywords = Keywords;
}
}
If you don't wanna cast you can do some thing like this:
public <T extends zwave> T Find(List<T> Zwave,List<List<String>> listofinputstrings)
{
for(List<String> lst: listofinputstrings)
{
for(String str: lst)
{
for (T rm: Zwave)
{
if(rm instanceof Scene){
Method method=null;
try {
method = rm.getClass().getMethod("getKeyword");
if ( method.invoke(rm).equals( str.toLowerCase()))
{
return rm;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
NOte:define getKeyword method in Scene class:
I can customize it more with the help of java.lang.reflect. You would not even need to use instance of Scene. But I think you can do it yourself. And hope it will help.
use Reflection API to call at run time.
You need to be using a getter method. When you say rm.keyword, that's referring to a constant (zwave.keyword), which is the empty string. When you cast to Scene, the compiler sees that it's a field and looks it up instead.
Generally, you should make fields like name and keyword private unless you have a specific reason not to and use getter and setter methods to manipulate them.
The variables defined in the interface are final static public even though you didn't explicitly define. When the variable is final, once the value is assigned you cannot reassign it again.
Since you have defined as empty string ("") it will take that value. But you define the variable again in Scene class. So when you cast to Scene object will refer this variable and not the variable in the interface. Otherwise it refers to interface variable.

Categories

Resources