I used the method below to make a copy of a list, as you can see the output, they are independent. Did I get something wrong? or are they really independent? because I did some research on the internet, and it told me this method should pass-by-reference (which list 'a' and 'copy' should be dependent).
public static void main(String[] args) {
ArrayList<String> a = new ArrayList<>(Arrays.asList("X", "X"));
ArrayList<String> copy = new ArrayList<>(a);
copy.set(0, "B");
copy.remove(copy.size()-1);
System.out.println(a);
System.out.println(copy);
}
Output:
[X, X]
[B]
As per the documentation, the ArrayList copy constructor:
Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
Modifying one list has no effect on the other, which your code confirms.
Yes, this method should pass-by-reference (which list 'a' and 'copy' should be dependent). But these two operations don't prove this.
copy.set(0, "B");
copy.remove(copy.size()-1);
See if the following code helps you understand:
public static void main(String[] args) {
Process process = new Process(1);
Process process2 = new Process(2);
ArrayList<Process> a = new ArrayList<>(Arrays.asList(process, process2));
ArrayList<Process> copy = new ArrayList<>(a);
copy.get(0).id = 10;
// This proves that both ArrayLists maintain the same Process object at this point
// output:
// [Id:10, Id:2]
// [Id:10, Id:2]
System.out.println(a);
System.out.println(copy);
// copy.remove(copy.size() - 1) or copy.set(0, process3) doesn't affect another ArrayList
Process process3 = new Process(3);
process3.id = 100;
copy.set(0, process3);
copy.remove(copy.size() - 1);
// output:
// [Id:10, Id:2]
// [Id:100]
System.out.println(a);
System.out.println(copy);
}
static class Process {
public int id;
public Process(int id) {
this.id = id;
}
#Override
public String toString() {
return "Id:" + id;
}
}
Related
This is mainly a question intended for me to learn about various performant ways of filtering and assigning objects to Lists.
Assume
public class A implements Comparable<A> {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Override
public int compareTo(A o) {
return o.getId().compareTo(this.getId());
}
}
public class B implements Comparable<B>{
private String id;
private List<A> aList = new ArrayList<>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void addA(A a)
{
aList.add(a);
}
#Override
public int compareTo(B o) {
return o.getId().compareTo(this.getId());
}
}
public class Main {
public static void main(String[] args) {
SortedSet<A> aSet = new TreeSet<>();
SortedSet<B> bSet = new TreeSet<>();
for(int i=0;i<100000;i++)
{
UUID uuid = UUID.randomUUID();
String uuidAsString = uuid.toString();
A a1 = new A();
a1.setId(uuidAsString);
aSet.add(a1);
A a2 = new A();
a2.setId(uuidAsString);
aSet.add(a2);
B b = new B();
b.setId(uuidAsString);
bSet.add(b);
}
//this is where the performance part comes in
//scenario: For each B I want to find A whose Id matches B's Id, and assign it to B
//assume B can have 1-5 instances of A (even though for this example I only initialized 2)
bSet.parallelStream().forEach(b -> {
aSet.parallelStream().filter(a -> {
return b.getId().equals(a.getId());
}).forEach(a -> {
b.addA(a);
});
});
}
}
The solution I came up with was to combine parallelstreams and filters to find the matching IDs between the two types of objects and then to loops through the filtered results to add the instances of A to B.
I used TreeSets here because I thought the ordered IDs might help speed things up, same reason I used parallelStreams.
This is mostly abstracted out from a scenario from a project I am doing at the office which I cant post here. The classes in the actual project have a lot more variables, and in the worst case - have sublists of lists (I resolved that using flatMaps in streams).
However my inexperienced gut tells me there is a more performant way to solve this problem.
I am primarily looking for practical ways to speed this up.
Some ways I thought of speeding this up:
Switch the lists and sets to Eclipse Collections
Assuming the starting point of these classes are CSV files -> Maybe write an apache spark application that will map these(I assumed that Spark could have some internal clever way of doing this faster than Streams).
I dunno......write them all to sql tables....map them via foreign keys and then query them again?
Speed is the name of the game, solutions using vanilla java, different librarys (like Eclipse Collections), or entire engines like Spark are acceptable
Assume the minimum list size is atleast 50,000
Bonus complexity: You can add another class 'C', with multiple instances of 'B' in it. My inexperienced self can only think of writing another similar streaming operation as A->B and run it after the first stream is done. Is there a way to combine both A->B and B->C operations together so that they happen at once. That will definitely speed things up.
Sorry about my inexperienced self and sorry again if this is a duplicate too
In your code, you use b.addA(a); where b is an instance of B while B doesn't have a method addA(A). Is B supposed to keep a list of A's?
However, the answer to your question is hashing. You are looking for a multimap, to be specific. As a quick fix you can use a TreeMap that stores a List of A's by their id:
public static void main(String[] args) {
TreeMap<String, ArrayList<A>> aSet = new TreeMap<>();
ArrayList<B> bSet = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
UUID uuid = UUID.randomUUID();
String uuidAsString = uuid.toString();
A a1 = new A();
a1.setId(uuidAsString);
ArrayList<A> list = aSet.get(a1.getId());
if (list == null) {
list = new ArrayList<>();
aSet.put(a1.getId(), list);
}
list.add(a1);
A a2 = new A();
a2.setId(uuidAsString);
list = aSet.get(a2.getId());
if (list == null) {
list = new ArrayList<>();
aSet.put(a2.getId(), list);
}
list.add(a2);
B b = new B();
b.setId(uuidAsString);
bSet.add(b);
}
for (B b : bSet) {
System.out.println(aSet.get(b.getId()));
}
}
Please note that this isn't a good implementation and instead you should write your own multimap or use the one in guava
The problem is as follows:
6 words are to be displayed on the screen. These words are chosen at random from a list. When I wrote the code, I didn't get any error, but when I ran it in eclipse, I got the following gibberish result in the console "package.wordsContainer#659e0bfd".
What did I do wrong?
public class wordsContainer {
Collection<String> wordList = new ArrayList<String>();
public void wordGroup1() {
wordList.add("Ant");
wordList.add("Almond");
wordList.add("Atom");
wordList.add("Affair");
wordList.add("Ample");
wordList.add("Blue");
wordList.add("Black");
wordList.add("Bronze");
wordList.add("Beauty");
wordList.add("Beautiful");
wordList.add("Batter");
wordList.add("Crazy");
}
public Collection<String> getRandomWords() {
wordGroup1();
LinkedList<String> wordLinkedList = new LinkedList<String>(wordList);
ArrayList<String> subList = new ArrayList<String>();
int i = 0;
while (i < 6) {
int index = (int) Math.random() * 10;
if (!subList.contains(wordLinkedList.get(index))) {
subList.add(wordLinkedList.get(index));
i++;
}
}
return subList;
}
}
public class wordsContainerTest {
public static void main(String[] args) {
wordsContainer list1 = new wordsContainer();
list1.wordGroup1();
System.out.println(list1);
System.out.println(list1.getRandomWords());
}
}
It's not gibberish, hexadecimal representation of the hash code of the object wordsContainer
That result is from the line
System.out.println(list1); //wordsContainer
Not from ArrayList.
In order to work properly you need to override toString method in your class wordsContainer
To understand what exactly is "package.wordsContainer#659e0bfd" read the answer I wrote long back.
https://stackoverflow.com/a/17878495/1927832
Apart from that, please follow java naming conventions, Class names starts with Capital letter.
System.out.println(list1); //wordsContainer
You can't print out objects directly, you will just print out the reference to the place in memory where the object is saved, which is that weird output you are getting. You have to override the toString() method in your object or print out the properties of the object that you want individually.
I'm new to java and am having issues understanding how to populate an array with object manually. Reason I wan't to do this manually is because I have 40 objects I need to create where 20 object go to arrayOne and other 20 objects go to arrayTwo. Also each object has a unique parameter like "Texas" or "Canada" that needs to be set.
I would usually create an array like this:
long[] arrayOne;
arrayOne = new long[20];
and than populate it with, lets say numbers through a loop or manually. However now I am dealing with objects and am struggling to figure it out, I tried looking up answers here at StackOverflow, but was not able to understand what was going on there exactly.
If it helps, this is a constructor for my object
// Plane Constructor
public Plane (int i, String dest, String airl, String airc, double t) {
planeID = i;
destination = dest;
airline = airl;
aircraft = airc;
time = t;
}// END Plane Constructor
I would suggest using an ArrayList instead of an array, because a list can grow but an array is a fixed size. However, to answer your question:
Plane[] arrayOne = new Plane[20];
Plane[] arrayTwo = new Plane[20];
arrayOne[0] = new Plane(1001, "Timbuktu");
arrayOne[1] = new Plane(2930, "Siberia");
// etc.
arrayTwo[0] = new Plane(2019, "France");
arrayTwo[1] = new Plane(1222, "Italy");
// etc.
If you used an ArrayList it would be:
List<Plane> arrayOne = new ArrayList<Plane>();
planes.add(new Plane(1001, "Timbuktu"));
planes.add(new Plane(2930, "Siberia"));
// etc.
Or, if you're really fancy:
List<Plane> planes = new ArrayList<Plane>() {{
add(new Plane(1001, "Timbuktu"));
add(new Plane(2930, "Siberia"));
}};
In all cases you can iterate over the contents as follows:
for (Plane plane : arrayOne) {
System.out.println(plane.getDestination());
}
Plane[] array = new Plane[10];
array[0] = new Plane(/*specify your parameters here*/)
Check out the chapter 10 of Java Language Specification.
You have to declare an array of objects (in this case Plane) just like you declare array of long - Plane[] arrayOne = new Plane[20];. Then you can access the elements using indices in the same manner. If you really have to populate it manually, you should do something like:
arrayOne[0] = new Plane(1, "foo", "bar", "baz", 1.0);
arrayOne[1] = new Plane(2, "fooo", "baar", "baaz", 2.0);
There are only two things that differ from the usage of Object[] array from long[] - type of the array and fact that at some point you have to use constructors to create objects. You can use a previously created object though.
U first create the Plane array:
Plane[] planes = new Plane[20];
then each object:
planes[0] = new Plane(...);
...
You can use a common interface if the elements of your array are not necessarily instances of Plane.
For instance:
package test;
public class Main {
public static void main(String[] args) {
Flyer[] flyers = new Flyer[] { new Plane(), new Bird() };
for (Flyer f: flyers) {
// you can only access method "fly" here, because it's the only
// method defined in your interface, but nothing
// stops you from adding more methods, as long as you implement
// them in the (non-abstract) classes
f.fly();
}
}
}
class Plane implements Flyer {
// TODO id, destination, airline, etc. getters/setters
#Override
public void fly() {
System.out.println("Weeee I'm flying!");
}
}
class Bird implements Flyer {
// TODO whatever properties / getters / setters
#Override
public void fly() {
System.out.println("Chirp chirp");
}
}
interface Flyer {
void fly();
}
Output:
Weeee I'm flying!
Chirp chirp
I know that there isn't way to access to the links of variables in java (like in &C or &php). But for example I have such task:
public class JustTest {
private int n = 1;
private int x = 10;
public int[] getIntegers() {
return new int[] { n, x };
}
public void filledInteger() {
int[] vals = getIntegers();
System.out.println("Before change");
System.out.println(Arrays.toString(vals));
vals[0] = 2;
vals[1] = 20;
System.out.println("After change");
System.out.println(Arrays.toString(vals));
System.out.println("Values of name & xml");
System.out.println(n);
System.out.println(x);
System.out.println("calling getIntegers");
System.out.println(Arrays.toString(getIntegers()));
}
public static void main(String[] args) {
JustTest t = new JustTest();
t.filledInteger();
}
}
The result is:
Before change
[1, 10]
After change
[2, 20]
Values of name & xml
1
10
calling getIntegers
[1, 10]
So, I want to change values of "n" and "x" fields of the class instance. I can't do this by setting straightly (this->n = 20;), because I may dont know what fields do I have. Only method getIntegers knows.
(No in this code, but for example I have child class with its own fields and in the parent class I have a method filledInteger() which should change specified properties of the child class ( he knows about this properties from the method getIntegers which is abstract in the parent class and implemented in the child class))
Here is simple implementation (without inheritance), using links in php
<?php
class JustTest {
private $n = 1;
private $x = 10;
public function getIntegers() {
return array( &$this->n, &$this->x );
}
public function filledInteger() {
$vals = $this->getIntegers();
echo("Before change" . "<br/>");
echo(print_r($vals, true) . "<br/>");
$vals[0] = 2;
$vals[1] = 20;
echo("After change" . "<br/>");
echo(print_r($vals, true) . "<br/>");
echo("Values of n & x". "<br/>");
echo $this->n , "<br/>";
echo $this->x , "<br/>";
echo("call getIntegers again" . "<br/>");
echo(print_r($this->getIntegers(), true) . "<br/>");
}
}
$t = new JustTest();
$t->filledInteger();
?>
The result is:
Before change
Array ( [0] => 1 [1] => 10 )
After change
Array ( [0] => 2 [1] => 20 )
Values of n & x
2
20
call getIntegers again
Array ( [0] => 2 [1] => 20 )
That is what I exactly need. Im just curious how do I implement this in java
Hope you understood.
Next example:
public abstract class ParentTest {
abstract int[] getIntegers();
public void fillIntegers(int[] newIntegers) {
int[] integersOfChild = getIntegers();
for (int i = 0; i < integersOfChild.length; i++) {
integersOfChild[i] = newIntegers[i];
}
}
}
public class ChildTest extends ParentTest {
private int x;
private int y;
#Override
int[] getIntegers() {
return new int[] {x, y};
}
}
public class UseTest {
void main() {
List<ParentTest> list;
for (ParentTest item : list) {
item.fillIntegers(myItegers);
}
}
}
This is what I need. I have a list of ParentTest instances (it may be ChildTest, or ChildTest2, or ChildTest3; but they all children of a ParentTest) and I need to fill all fields with my integer values, but I dont know if items in the list instances of a ChildTest, or ChildTest2, or ChildTest3 class
How do I implement this in Java?
With great pain via the Reflection API. If you want to write code like this, the best idea is to use another language.
Consider programming in Groovy instead. You can use array syntax to directly access class members by name: t["n"] = 2; This works with legacy Java code, so there is no need to modify TestClass to support this usage.
The concept you are talking about is called pass by reference. Java has for the most part abandoned it - it creates too many side-effects, like the one you are seeing here.
The issue is that while unfortunately you can't do this here, it actually prevents a huge number of unintentional bugs being released.
What about something like that:
public final class JustTest {
private final Map<String, Object> fields;
public void filledInteger() {
System.out.println("Before change\n" + this.fields);
fields.put("N", 2);
fields.put("X", 20);
System.out.println("After change\n" + this.fields);
System.out.println("Values of name & xml\n" + fields.get("N")
+ "\n" + fields.get("X"));
}
private JustTest() {
this.fields = Maps.newHashMap(); // guava
fields.put("N", 1);
fields.put("X", 10);
}
public static void main(String[] args) {
final JustTest t = new JustTest();
t.filledInteger();
}
}
You can't do individual fields without reflection, but you can change the contents of collections. Note that this is not really intended behavior, but rather something you have to be careful of when using collections.
This outputs 5 3 2 4 2 4
public class Test
{
public Vector<Integer> args = new Vector<Integer>();
public void fillArgs()
{
args.add(5);
args.add(3);
}
public Vector<Integer> getArgs()
{
return args;
}
public static void main(String args[])
{
Test s = new Test();
s.fillArgs();
Vector<Integer> temp = s.getArgs();
for (Integer i : temp)
System.out.println(i);
temp.setElementAt(2, 0);
temp.setElementAt(4, 1);
for (Integer i : temp)
System.out.println(i);
for (Integer i : s.getArgs())
System.out.println(i);
}
}
Your php example does not return an array of ints, but rather an array of int pointers. This is NOT something you can do in Java, in fact, this is NOT something you want to do in Java. Give a use case, and there is likely a better way to solve the problem you have.
If you want to return an object that others can affect and that are contained as member variables, do that. An ArrayList, HashMap, etc... there are plenty of things that can fit your needs. If you are given someone elses class and you must stick your nose in their code, you can get around their private declaration doing the following:
public void setN(JustTest j, int n) {
//You would handle some exceptions here also
Field f = JustTest.class.getDeclaredField("n");
f.setInt(j, n);
}
This is a trivial question, but my Java is rusty and it's got me stumped; I am getting a null-pointer exception. It may be obvious what I am trying to do based on the code below - but I will explain...
I need an array of objects and I don't want to create another file. For this trivial project, I do not want getters and setters. I have seen an example similar to below that uses a linked list based on a class that is located inside of another class. But, I am more proficient with arrays than linked lists, so I want to use arrays.
public class Ztest {
Stuff[] st = new Stuff[2];
public Ztest(){
}
class Stuff{
public String x;
public boolean y;
public Stuff(){}
}
public static void main(String args[]){
Ztest test = new Ztest();
test.st[0].x = "hello";
test.st[0].y = true;
test.st[1].x = "world";
test.st[1].y = false;
System.out.println(test.st[0].x);
System.out.println(test.st[0].y);
System.out.println(test.st[1].x);
System.out.println(test.st[1].y);
}
}
You need to assign a value to st[0] and st[1] first:
test.st[0] = new Stuff();
test.st[1] = new Stuff();
Java allocates null for object values in new arrays. You'll need something like test.st[0] = new Stuff() before using it.
You need test.st[0]=new Stuff(); etc. since Stuff[] st = new Stuff[2]; creates an array but the elements (references) are still null.
In terms of C/C++ this would be Stuff** st = new Stuff*[2];, i.e. the st is an array of pointers to Stuff instances, whereas the pointers still point to nothing yet.
You need to put an instance of Stuff into test.st[0] and test.st[1].
You can try this if you want to use a list.
static class Stuff {
public String x;
public boolean y;
// generated by my IDE.
Stuff(String x, boolean y) {
this.x = x;
this.y = y;
}
// generated by my IDE.
public String toString() {
return "Stuff{" + "x='" + x + '\'' + ", y=" + y + '}';
}
}
public static void main(String args[]) {
List<Stuff> list = new ArrayList<Stuff>();
list.add(new Stuff("hello", true));
list.add(new Stuff("world", false));
System.out.println(list);
}
prints
[Stuff{x='hello', y=true}, Stuff{x='world', y=false}]