Unfortunately my Java knowledge is somewhat lacking so this is somewhat of a beginner's question but I can't seem to figure out how I can do this.
Essentially I have a method that creates and populates an ArrayList. The said populated list is something that I want to use in a different method and potentially another class. I think that it is a class level variable I want to save it as but I'm not sure how to do this. The code below will make it more clear.
public class JenAcc {
private final String endpointUrl = "http://a-url/";
private String uri = "api/json";
public static void main(String[] args) {
JenAcc obj = new JenAcc();
obj.jsonRun();
}
public void jsonRun() {
ArrayList<String> abbrevList = new ArrayList<>();
ArrayList<String> urlList = new ArrayList<>();
try {
RestServiceClient client = RestServiceClient.getClient(endpointUrl);
Response response = client
.path(uri)
.accept(MediaType.APPLICATION_JSON)
.get();
String s = (String) response.getEntity();
JobList jjj = JSONResponseHandler.mapJSONToResponse(s, JobList.class);
for (int i = 0; i < jjj.getJobs().size(); i++) {
if (jjj.getJobs().get(i).getName().contains("services"){
abbrevList.add(jjj.getJobs().get(i).getName().replace("services", ""));
urlList.add(jjj.getJobs().get(i).getUrl());
} else i++;
}
System.out.println(abbrevList);
System.out.println(urlList);
} catch (Exception e) {
e.printStackTrace();
}
}
}
So essentially I want to have a way to make use of that list outside of that method, in another method or class. How would I go about doing that?
Thanks for your patience.
Declare the lists as member variables,
& define accessor methods to reach out to them from outside the class:
public class JenAcc {
private List<String> abbrevList = new ArrayList<>();
private List<String> urlList = new ArrayList<>();
...
public List<String> getAbbrevList() {
return abbrevList;
}
public List<String> geturlList() {
return urlList;
}
}
& to access the lists from outside the class :
JenAcc jenacc = new JenAcc(); // initialization
List<String> urls = jenacc.geturlList(); // Use the accessor method defined above
// Same goes for the other list
If it should be a class-level member, then just declare it where you declare your other class-level members:
private final String endpointUrl = "http://a-url/";
private String uri = "api/json";
ArrayList<String> abbrevList = new ArrayList<>();
ArrayList<String> urlList = new ArrayList<>();
(And of course remove the local declarations from the method.) Naturally, this will affect the scope of those values. Running the method more than once on any given instance of the object could have unintended side-effects, but that's really up to the logic of whatever you need to do to/with these values.
At that point any other code in the object will be able to access those values. If they need to be accessed by other objects as well, add a getter:
public ArrayList<String> getAbbrevList() {
return this.abbrevList;
}
There are of course other approaches as well, it all really depends on how your object should behave rather than how your method should behave. For example, maybe it shouldn't be a class-level member but should instead be returned by the method? It's a question for the semantics of the system you're building. And names like "JenAcc" and "jsonRun" don't really convey much about those semantics.
Related
I created an object N, which has some attributes, like this:
public class LogEvidence {
private String comment;
private String url;
private String time;
public LogEvidence(String comentario, String url, String tiempo) {
super();
this.comment = comentario;
this.url = url;
this.time = tiempo;
}
public String getComentario() {
return comment;
}
public void setComentario(String comentario) {
this.comment = comentario;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTiempo() {
return time;
}
public void setTiempo(String tiempo) {
this.time = tiempo;
}
#Override
public String toString() {
return "LogEvidence [comentario=" + comment + ", url=" + url + ", tiempo=" + time + "]";
}
}
Now I want to do something like this:
ArrayList<LogEvidence>log = new ArrayList<LogEvidence>();
I want go through the list and add all the attributes to my object, I mean something like this:
log.setComment("comment one");
log.setUrl("http://google.com");
log.setTime("04:20");
Maybe this is not possible and I have to do something like the following?
List list= new List();
LogEvidence object1= new LogEvidence ();
object1.setComment("comment");
object1.setUrl("http://url.com");
object1.setTime(20);
lista.add(object1);
This is how you can do it:
Create an object of LogEvidence.
LogEvidence logEvidence = new LogEvidence();
logEvidence.setComentario("comment one");
logEvidence.setUrl("http://google.com");
logEvidence.setTiempo("04:20");
and add it into the array list.
log.add(logEvidence);
So, you can then create more objects and keep putting in the list. Since your list is named as log, so that is why you will add in log
Explaining it a little more, it should be something like this:
List<LogEvidence> logEvidenceList = new ArrayList<>();
LogEvidence logEvidence1 = new LogEvidence();
logEvidence1.setComentario("comment one");
logEvidence1.setUrl("http://google.com");
logEvidence1.setTiempo("04:20");
logEvidenceList.add(logEvidence1);
LogEvidence logEvidence2 = new LogEvidence();
logEvidence2.setComentario("comment one");
logEvidence2.setUrl("http://google.com");
logEvidence2.setTiempo("04:20");
logEvidenceList.add(logEvidence2);
....
....
....
Or through constructor call, this will become more concise and readable.
List<LogEvidence> logEvidenceList = new ArrayList<>();
LogEvidence logEvidence1 = new LogEvidence("comment one","http://google.com","04:20");
logEvidenceList.add(logEvidence1);
LogEvidence logEvidence2 = new LogEvidence("comment one","http://google.com","04:20");
logEvidenceList.add(logEvidence2);
....
....
....
Now, when you want to retrieve objects from the list, you can traverse the list and get one by one like;
for (LogEvidence evidence : logEvidenceList) {
System.out.println(evidence);
}
For more information about ArrayList
As Kon commented, you are trying to act upon an object that will be within the list, rather than the list itself.
There are a few ways to do this, but since you have a parameterized construtor, the easiest would be this:
ArrayList<LogEvidence> log = new ArrayList<LogEvidence>();
log.add(new LogEvidence("comment one", "http://url.com", "04:20");
What's being done:
We create the list with new ArrayList<LogEvidence>() and assign it to a variable called log.
Then, we create a new LogEvidence object, already assigning it's data through it's constructor's parameters, with new LogEvidence("comment one","http://url.com","04:20").
Since it will be stored in the list, we can use it anonymously. We add it to the list directly, using the list's .add(E e) method, rather than assigning it to a variable.
You don't need to define or assign unnecessary variables, in this case.
And if you need to access any specific LogEvidence from the list, you can use the .get(int index) method. In this case, log.get(0), to return the first element, would return the object you just inserted in the example code above.
You can also use a FOR-EACH LOOP to act upon all objects in the list, in iterating manner. Here is an example that prints the list:
for (LogEvidence evidence : log) {
System.out.println(evidence);
}
I would like to use functional programming to copy data from a collection of one object to a collection of other objects.
I have been reading several Java 8 books and researching online. I am pretty sure I want to use stream(), but just about every example I have seen always iterates through a collection, does some processing on the objects in the collection, and uses println() to output the contents. No one seems to discuss how to deal with situations like the one described below.
Suppose we have the following objects:
public class ObjectA
{
private String someData;
private int moreData;
public String getSomeData()
{
return someData;
}
public void setSomeData(String sData)
{
someData = sData;
}
public int getMoreData()
{
return moreData;
}
public void setMoreData(int mData)
{
moreData = mData;
}
}
public class ObjectB
{
private String b_Data;
public String getB_Data()
{
return b_Data;
}
public void setB_Data(String bData)
{
b_Data = bData;
}
}
I want to create a collection of ObjectB objects whose b_data atributes are equal to the someData attributes in a collection of ObjectAs.
A reasonably good way to do this is illustrated in the code below:
public class Collector
{
public Collection<ObjectB> collectObjects(Collection<ObjectA> theAs)
{
// The use of an ArrayList is arbitrary. I might want to use any number
// of different lists or even different collections!
final Collection<ObjectB> theBs = new ArrayList<ObjectB>();
for(ObjectA obj : theAs)
{
final ObjectB bobj = new ObjectB();
bobj.setB_Data(obj.getSomeData());
theBs.add(bobj);
}
return theBs;
}
}
The code in the collectObjects() method will work, but it uses techniqhes of imperative programming. I would like to know how to make the collection of ObjectBs using functional techniques.
Is there a way to accomplish this using streams and lambdas?
This situation actually applies perfectly with the Stream API. What you want is to:
Make a Stream<ObjectA> which is a Stream of your input list, with theAs.stream().
Map each ObjectA in the Stream to an ObjectB with Stream.map.
Collect the result with Stream.collect into a new list using Collectors.toList().
This would be an implementation:
public Collection<ObjectB> collectObjects(Collection<ObjectA> theAs) {
return theAs.stream().map(obj -> {
final ObjectB bobj = new ObjectB();
bobj.setB_Data(obj.getSomeData());
return bobj;
}).collect(Collectors.toList());
}
Of course, you could create a constructor of ObjectB that takes obj.getSomeData() as parameter. It would simplify the code because then you could write:
public Collection<ObjectB> collectObjects(Collection<ObjectA> theAs) {
return theAs.stream().map(obj -> new ObjectB(obj.getSomeData())).collect(Collectors.toList());
}
obj -> new ObjectB(obj.getSomeData()) is called a lambda expression.
You can do it like this:
List<ObjectB> theBs = theAs
.stream()
.map(a-> {
final ObjectB bobj = new ObjectB();
bobj.setB_Data(a.getSomeData());
return bobj;
}).collect(Collectors.toList());
The a -> { ... } construct is a lambda, a construct that lets you pass some executable code into a method call.
The body of the lambda comes straight from the loop body in your second example.
GSON's toJson function takes a type argument which checks the Type when reflecting the object. This is useful for reflecting objects into a collection.
However, the only way I can find to obtain the Type is through an ugly set of coding contortions:
//used for reflection only
#SuppressWarnings("unused")
private static final List<MyObject> EMPTY_MY_OBJECT = null;
private static final Type MY_OBJECT_TYPE;
static {
try {
MY_OBJECT_TYPE = MyClass.class.getDeclaredField("EMPTY_MY_OBJECT").getGenericType();
} catch (Exception e) {
...
}
}
private List<MyObject> readFromDisk() {
try {
String string = FileUtils.readFileToString(new File(JSON_FILE_NAME), null);
return new Gson().fromJson(string, MY_OBJECT_TYPE);
} catch (Exception e) {
...
}
}
Is there a way of initializing the Type without referencing internal class variables? The pseudocode would looks something like this:
private static final Type MY_OBJECT_TYPE = TypeUtils.generate(List.class, MyObject.class);
The Javadoc for toJson looks to answer your question
typeOfSrc - The specific genericized type of src. You can obtain this type by using the TypeToken class. For example, to get the type for Collection, you should use:
Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
So in your instance.
private static final Type MY_OBJECT_TYPE = new TypeToken<List<MyObject>>(){}.getType();
It is also possible to do like this:
private static final Type MY_OBJECT_TYPE = TypeToken.getParameterized(List.class, MyObject.class).getType();
I put some value to ArrayList<"Object">
ArrayList<Object> mData = new ArrayList<Object>();
AdListData data = new AdListData();
data.Id = json_data.getInt("ad_uid");
data.User_id = json_data.getInt("user_id");
mData.add(data);
And after I need to convert ArrayList<"Object"> to ArrayList<"AdListData">
How can I do this? Example:
ArrayList<AdListData> array = new ArrayList<AdListData>();
array = mData;
Why I need to do this? I use AsyncTask and on onPostExecute a get data like this
protected void onPostExecute(ArrayList<Object> result) {
// Pass the result data back to the main activity
mDownloadCompleteListener.getDownloadCompleteState(result);
}
this example show that a get only on type of arraylist
ArrayList<Object>
OR
ArrayList<AdListData>
But in my case I want to use it for different Objects like this
ArrayList<Object> mData = new ArrayList<Object>();
if(mType == "get_ad_data")
{
AdListData data = new AdListData();
data.Id = json_data.getInt("ad_uid");
data.User_id = json_data.getInt("user_id");
mData.add(data);
}
else
{
AnotherClass data = new AnotherClass();
data.Id = json_data.getInt("ad_uid");
data.User_id = json_data.getInt("user_id");
mData.add(data);
}
return mData;
`
And when listener call I want to convert it in needed Array of objects
#Override
public void getDownloadCompleteState(ArrayList<Object> ad_list) {
// TODO Auto-generated method stub
ArrayList<AdListData> array = new ArrayList<AdListData>();
array = ad_list;
}
Check out java generics. When you pass in your array list, define it as ArrayList<T extends Object> or ArrayList<? extends Object>. Then when you're passing or getting values you can define T as the class of your choice or check if the object is an instance of the class you want. There's a ton of information and examples on java generics so you can find what fits your needs w/o me posting a bunch of examples.
I don't think it's possible to just automatically assign ArrayList<Object> to ArrayList<AdListData> since there is no guarantee that all of the data is of type AdListData.
Why you are making life too complicated..
Ever heard about Moduler Code, Interfaces, Abstract classes???
I ll suggest you to write one Interface or Abstract class over your AdListData and AnotherClass.. (I am assuming they share IS A relationship..) If not.. write two diff AsyncTasks for those.. and if they share common code you can use functions like utility functions..
doing this your code will be much more readable and simple..
now, to ans your question I ll just write some snippet..
public class Test {
int data;
public static <T extends Object> void foo(ArrayList<T> l) {
T firstObj = l.get(0);
if (firstObj != null) {
if (firstObj instanceof Test) {
System.out.println("yay.. I am list of test obj " + l);
} else {
System.out.println("m just another list.. :( " + l);
}
}
#Override
public String toString() {
return data + "";
}
public static void main(String[] args) {
ArrayList<Test> l = new ArrayList<Test>();
Test t1 = new Test();
t1.data = 1;
Test t2 = new Test();
t2.data = 2;
Test t3 = new Test();
t3.data = 3;
Test t4 = new Test();
t4.data = 4;
l.add(t1);
l.add(t2);
l.add(t3);
l.add(t4);
foo(l);
ArrayList<Integer> l2 = new ArrayList<Integer>();
l2.add(1);
l2.add(2);
l2.add(3);
l2.add(4);
foo(l2);
}
}
Imagine that I have this class:
public class Test
{
private String[] arr = new String[]{"1","2"};
public String[] getArr()
{
return arr;
}
}
Now, I have another class that uses the above class:
Test test = new Test();
test.getArr()[0] ="some value!"; //!!!
So this is the problem: I have accessed a private field of a class from outside!
How can I prevent this? I mean how can I make this array immutable? Does this mean that with every getter method you can work your way up to access the private field? (I don't want any libraries such as Guava. I just need to know the right way to do this).
If you can use a List instead of an array, Collections provides an unmodifiable list:
public List<String> getList() {
return Collections.unmodifiableList(list);
}
You must return a copy of your array.
public String[] getArr() {
return arr == null ? null : Arrays.copyOf(arr, arr.length);
}
Modifier private protects only field itself from being accessed from other classes, but not the object references by this field. If you need to protect referenced object, just do not give it out. Change
public String [] getArr ()
{
return arr;
}
to:
public String [] getArr ()
{
return arr.clone ();
}
or to
public int getArrLength ()
{
return arr.length;
}
public String getArrElementAt (int index)
{
return arr [index];
}
The Collections.unmodifiableList has already been mentioned - the Arrays.asList() strangely not! My solution would also be to use the list from the outside and wrap the array as follows:
String[] arr = new String[]{"1", "2"};
public List<String> getList() {
return Collections.unmodifiableList(Arrays.asList(arr));
}
The problem with copying the array is: if you're doing it every time you access the code and the array is big, you'll create a lot of work for the garbage collector for sure. So the copy is a simple but really bad approach - I'd say "cheap", but memory-expensive! Especially when you're having more than just 2 elements.
If you look at the source code of Arrays.asList and Collections.unmodifiableList there is actually not much created. The first just wraps the array without copying it, the second just wraps the list, making changes to it unavailable.
You can also use ImmutableList which should be better than the standard unmodifiableList. The class is part of Guava libraries that was create by Google.
Here is the description:
Unlike Collections.unmodifiableList(java.util.List), which is a view of a separate collection that can still change, an instance of ImmutableList contains its own private data and will never change
Here is a simple example of how to use it:
public class Test
{
private String[] arr = new String[]{"1","2"};
public ImmutableList<String> getArr()
{
return ImmutableList.copyOf(arr);
}
}
at this point of view you should use system array copy:
public String[] getArr() {
if (arr != null) {
String[] arrcpy = new String[arr.length];
System.arraycopy(arr, 0, arrcpy, 0, arr.length);
return arrcpy;
} else
return null;
}
}
You could return a copy of the data. The caller who chooses to change the data will only be changing the copy
public class Test {
private static String[] arr = new String[] { "1", "2" };
public String[] getArr() {
String[] b = new String[arr.length];
System.arraycopy(arr, 0, b, 0, arr.length);
return b;
}
}
The nub of the problem is that you are returning a pointer to a mutable object. Oops. Either you render the object immutable (the unmodifiable list solution) or you return a copy of the object.
As a general matter, finality of objects does not protect objects from being changed if they are mutable. These two problems are "kissing cousins."
Returning an unmodifiable list is a good idea. But a list that is made unmodifiable during the call to the getter method can still be changed by the class, or classes that are derived from the class.
Instead you should make it clear to anybody that extends the class that the list should not be modified.
So in your example it could lead to the following code:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
public static final List<String> STRINGS =
Collections.unmodifiableList(
Arrays.asList("1", "2"));
public final List<String> getStrings() {
return STRINGS;
}
}
In the above example I've made the STRINGS field public, in principle you could do away with the method call, as the values are already known.
You could also assign the strings to a private final List<String> field made unmodifiable during construction of the class instance. Using a constant or instantiation arguments (of the constructor) depends on the design of the class.
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
private final List<String> strings;
public Test(final String ... strings) {
this.strings = Collections.unmodifiableList(Arrays
.asList(strings));
}
public final List<String> getStrings() {
return strings;
}
}
Since Java 9, an immutable list can also be constructed from a static factory method List.of() which results in just a bit fewer imports and code:
With an alias being returned from getUsers() when the original users fields can be modified:
class Computer {
private String[] users = new String[] {"user1", "user2", "user3"};
public String[] getUsers;
String[] getUsers() {
return this.users;
}
}
Computer c = new Computer();
c.getUsers()[0] = "me";
for (String user: c.getUsers()) {
System.out.println(user);
}
Output:
me
user2
user3
Using the immutable list:
import java.util.List;
class Computer {
private String[] users = new String[] {"user1", "user2", "user3"};
public List<String> getUsers;
List<String> getUsers() {
return List.of(this.users);
}
}
Computer c = new Computer();
c.getUsers().set(0, "me");
for (String user: c.getUsers()) {
System.out.println(user);
}
Output:
user1
user2
user3
Yes, you should return a copy of the array:
public String[] getArr()
{
return Arrays.copyOf(arr);
}