I have a course class having one Hashmap. I'm trying to add values to the map with different objects. Map is common for all the objects so I marked it as Static still it shows weird behavior.
I have the following code -
class Course
{
static HashMap<Integer,List<String>> map;
Course()
{
map = new HashMap<>();
}
public boolean add(int id,String Course)
{
if(!map.containsKey(id))
{
map.put(id,new ArrayList<>());
}
try
{
List<String> temp = map.get(id);
temp.add(Course);
return true;
} catch (Exception e)
{
return false;
}
}
public void get()
{
System.out.println(map);
}
public static void main(String[] args)
{
Course c = new Course();
c.add(1, "abs");
c.add(2,"xyx");
c.add(1,"new");
c.add(3,"tye");
c.get();
Course c2 = new Course();
c2.add(1,"GP");
c2.add(2, "PT");
c2.get();
}
}
I have defined Hashmap as static because it is common for all the objects. But still, the new Hashmap is created for every instance.
Output
{1=[abs, new], 2=[xyx], 3=[tye]}
{1=[GP], 2=[PT]}
Because you initialize it in the constructor.
Don't. Just initialize it on the field:
static HashMap<Integer,List<String>> map = new HashMap<>();
(And remove the constructor).
And consider making the field final if you never intend to reassign it. This ensures that 1) you don't actually reassign it; 2) you actually do assign it once.
Related
I have an ArrayList<E>, where E has several subclasses. I want to remove the first instance of an object of subclass T.
My current implementation relies on an overridden equals(Object o) that looks at a constant that is unique to the subclass. Since objects of this subclass are interchangeable, I figured this would be much better than the usual implementations. See below.
public class E {
//Stuff
}
public class T extends E {
private static final String UNIQUE_STRING = "blah";
//More variables
public T() {
}
public static String getUniqueString() {
return UNIQUE_STRING;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (this.getClass() == o.getClass()) {
T t = (T) o;
if (this.getUniqueString().equals(t.getUniqueString())) return true;
}
return false;
}
//Also has hashCode() here somewhere, as well as other methods
}
import java.util.List;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
initialize();
}
private static void initialize() {
E t1 = new T();
E t2 = new T();
E t3 = new T();
List<E> list = new ArrayList<>();
list.add(t1);
list.add(t2);
list.add(t3);
list.remove(new T());
}
}
Using a Map<T, Integer> (or similar) is not feasible because list is going to contain other subclasses of E, not just T, and objects of those other subclasses differ in many respects. Only instances of T are, for all intents and purposes, interchangeable.
Separating instances of T from the list and using a Map<T, Integer> would be a major headache due to indexing and whatnot.
Finally, searching each object one by one until I found an instance of T (by using getClass() and the literal name of the class) seems like it'd be even worse.
My concern is that creating new objects to do this, while functional, is highly inefficient and potentially "dangerous". Is there a better way of achieving this?
using instanceof is probably what you are looking for.
class Scratch {
static class E {
//Stuff
}
static class T extends E {
}
public static void main(String[] args) {
final var arrayList = new ArrayList<>(List.of(new E(), new E(), new E(), new T(), new T(), new E()));
for (E e : arrayList) {
if (e instanceof T) {
arrayList.remove(e);
break;
}
}
System.out.println(arrayList);
}
}
[Scratch$E#5b1d2887, Scratch$E#46f5f779, Scratch$E#1c2c22f3, Scratch$T#18e8568, Scratch$E#33e5ccce]
This will continue to work work on subclasses of T as well.
if you have an extensive list and you're looking for a faster way of doing things, you can use parallel streams of java 8
public static void main(String[] args) {
final var arrayList = new ArrayList<>(List.of(new E(), new E(), new E(), new T(), new T(), new E()));
var listWithoutTinstances = arrayList.parallelStream()
.filter(e -> e instanceOf T)
.collect(Collectors.toList());
}
make sure you have to use parallel stream instead of simple one , you can check this to learn more: https://www.baeldung.com/java-when-to-use-parallel-stream
Every time I call the method inserimentoVoto to add elements in a list contained in the object Studente, the data is overwritten I know it's easy but I just started to code.
public class Run {
public static void main(String[] args) {
Gestione g = new Gestione();
Studente s = new Studente();
g.inserimentoVoto(s);
}
}
This is the method
public void inserimentoVoto(Studente s) {
Voto v = new Voto();
System.out.println("Insert value");
v.setVoto(scanner.next());
System.out.println("Insert name");
v.setMateria(scanner.next());
v.setDataVoto(new Date());
s.setListaVoti(new ArrayList<Voto>());
s.getListaVoti().add(v);
}
s.setListaVoti(new ArrayList<Voto>());
You are creating a new ArrayList everytime
The above line should be only done once in the Studente class.
public class Studente
{
private ArrayList<Voto> arr = new ArrayList<Voto>();
... Other data ...
public ArrayList<Voto> getListaVoti()
{
return arr;
}
... Other methods ...
}
You do not need a setListaVoti at all - because it's done only once.
In the inserimentoVoto method, you only need
s.getListaVoti().add(v);
I am trying to loop through a HashMap, then for each key I want to access the object (Shipment) that is associated to the key and access my array list for further analysis purposes. Each object/key in HashMap has the same array list (metricList). I cannot seem to access it, though I have checked the private/public thing. Can someone point me in the right direction?
I think I need to maybe get the class of my object and then use the method "getList"... I tried with no luck.
This is a sample of the code (removed irrelevant parts) if it helps:
This is my object:
public class Shipment{
//Members of shipment
private final String shipment;
public Date creationDate;
public int creationTiming;
public int processingTiming;
public ArrayList<Integer> metricList;
public void createArrayList() {
// create list
metricList = new ArrayList<Integer>();
// add metric to list
metricList.add(creationTiming);
metricList.add(processingTiming);
}
public ArrayList<Integer> getList() {
return metricList;
}
}
This is the class where I create a hashMap and run through different analysis:
public class AnalysisMain {
public static Map<String, Shipment> shipMap = new HashMap();
public static void main(String[] args) {
try {
... // Different calls to analysis
}
catch {}
}
}
This is where the issue occurs (it does not recognize that I already have a "metricList", asking if I want to create local variable)
public class Metric_Analysis{
public static void analyze() throws Exception{
ResultSet rs;
try {
rs = getSQL("SELECT * FROM TEST_METRICS");
}
catch(Exception e) {
//Pass the error
throw new java.lang.Exception("DB Error: " + e.getMessage());
}
Iterator<Map.Entry<String, Shipment>> iterator = shipMap.entrySet().iterator();
while(iterator.hasNext()){
Iterator<String> metricIterator = metricList.iterator();
//Above is the Array List I want to access and loop through
//I will then perform certain checked against other values on a table...
while (metricIterator.hasNext()) {
//I will perform certain things here
}
}
}
}
You need to get the List out of your Shipment.
You can access the object from the iterator with: iterator.next();
This will also set the pointer to the next Entry in your List/Map.
Change your code:
Iterator<Map.Entry<String, Shipment>> iterator = shipMap.entrySet().iterator();
while(iterator.hasNext()){
// Get the Entry from your Map and get the value from the Entry
Entry<String, Shipment> entry = iterator.next();
List<Integer> metricList = entry.getValue().getList();
Iterator<String> metricIterator = metricList.iterator();
//Above is the Array List I want to access and loop through
//I will then perform certain checked against other values on a table...
while (metricIterator.hasNext()) {
//I will perform certain things here
}
}
I am making a particle emitter.
Every "Rendered" object is stored in a HashSet, and when there's lots of particles on the screen, the console spits out concurrent modification exceptions. I usually have a short lifetime on these particles so they get deleted after several seconds, but I am sure this could potentially be a problem in the future. How can I fix this?
EDIT: Code:
public class UpdatedManager {
private static Set<Updated> updates = new HashSet<>();
private UpdatedManager() {}
public static Set<Updated> getUpdates() {
return new HashSet<Updated>(updates);
}
public static boolean registerUpdated(Updated u) {
return updates.add(u);
}
public static boolean unregisterUpdated(Updated u) {
return updates.remove(u);
}
public static void update() {
for (Updated up : new HashSet<Updated>(updates))
up.update();
}
public static Set<GameObject> getGameObjects() {
Set<GameObject> objs = new HashSet<>();
for (Updated up : new HashSet<Updated>(updates)) {
if (up instanceof GameObject)
objs.add((GameObject) up);
}
return objs;
}
public static Set<GameObject> getGameObjectsByName(String name) {
Set<GameObject> objs = new HashSet<>();
for (GameObject go : new HashSet<GameObject>(getGameObjects())) {
if (go.getName() != null && go.getName().equals(name))
objs.add(go);
}
return objs;
}
public static Set<Particle> getParticles() {
Set<Particle> parts = new HashSet<>();
for (Updated up : new HashSet<Updated>(updates)) {
if (up instanceof Particle)
parts.add((Particle) up);
}
return parts;
}
}
A ConcurrentModificationException means you modified the set while iterating over it. It does not mean the set is full.
For example, the following code will throw a ConcurrentModificationException:
Set<String> set = new HashSet<>();
set.add("Hello");
for(String s : set)
set.add(s+" world");
Note that you are not guaranteed to get a ConcurrentModificationException, so you should avoid catching it. You should instead fix your code so that it doesn't cause the problem.
What makes you think that the set is full?
Concurrent modification exceptions mean that the set is being accessed by different threads in an unsafe manner.
Try a synchronised set using the Collections utilities
HashSet hashSet = new HashSet();
Set set = Collections.synchronizedSet(hashSet);
or use the synchronized keyword for the method accessing the set.
I have a question on copy construction in Java. Consider the following class;
In the copy constructor I can say new(Integer(other.id)) to get a new integer object being passed to the constructor, but I can't say new T(other.data) as the compiler will say cannot instantiate the type T. How can I make sure that when the generic item is copy constructed that it will not just pass a reference such that the 2 objects will share the underlying data.
Also, in the getLinks method it is doing a new and creating a new object of the list but is that going to deep copy and create new object of the items contained in the list or will it just contain references to the existing objects list items such that you have 2 lists both pointing to the same data. See below the comments / code. Thanks in advance for your expertise.
class DigraphNode<T>
{
Integer id;
T data;
ArrayList<DigraphNode<T> > links;
public DigraphNode(Integer i)
{
id = i;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(Integer i, T d)
{
id = i; data = d;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(DigraphNode<T> other)
{
other.id = new Integer(other.id);
other.data = other.data; // line in question
this.links=other.getLinks(); // also will create a new list with references
// or will it deep copy the items contained in the list?
// see getLinks() method below
}
public void setData (T d ) { data = d; }
public void addLink (DigraphNode<T> n) { links.add(n); }
public void addLinks (ArrayList<DigraphNode<T> > ns) { links.addAll(ns); }
public ArrayList<DigraphNode<T> > getLinks()
{
return new ArrayList<DigraphNode<T> >(links);
}
public void printNode()
{
System.out.print("Id: " + id + " links: ");
for ( DigraphNode<T> i : links )
{
System.out.print(i.id + " ");
}
System.out.println();
}
}
You can't instantiate new T(other.data) as you tried, but you can clone() other.data if T implements Cloneable
Every call to getLinks() will create a new list with reference to object contained to links, you have to different lists with same reference inside (so change one reference object property will reflect to other list object because they are the same object)
About ArrayList<> links = new ArrayList<>(); from Oracle doc:
Initializer blocks for instance variables look just like static
initializer blocks, but without the static keyword:
{
// whatever code is needed for initialization goes here
}
The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of
code between multiple constructors.
EDIT:
You can define a static method (copy) that try to use all possible strategies to copy generic object; the best approch is to define your own interface to separate your own stategy and simulate a sort of copy-constructor (you can reuse copy method if you want), else via serialization or, as last try, using cloning (but clone() is full of pitfall).
You can also use this libraries:
Cloning
Commons-SerializationUtils
interface MyCloneableInterface<T> {
T duplicate(T object) throws CopyException;
}
public static <T> T copy(T data) throws CopyException {
if(data == null) return null;
if(data instanceof MyCloneableInterface) {
return ((MyCloneabeInterface)data).duplicate(data);
}
if(data instanceof Serializable) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (CloneExample) ois.readObject();
}
catch(...) {//rethrow}
}
if(data instanceof Cloneable) {
try {
return (T)data.clone();
}
catch(CloneNotSupportedException e) {//rethrow}
}
// else you can look for copy-constructor via reflection or
// cloning object field-by-field via reflection...
}
First Question: You cannot instantiate a generic instance (in other words call T's constructor). You should either define T implements Cloneable and call clone or use another interface of your own if T is always under your control. There are many pitfalls to this method, I'd suggest you first read about this interface and familiarize yourself with the pitfalls (you can find a great chapter on this, in "Effective Java" book). Also, it is not always that you can guarantee that this class will use T types which are Cloneable.
About links - you're instantiating it in the beginning and then override it in the constructor - Why? Remove the initialization. The way your getLinks works is not by creating a deep copy. Meaning - you'll get a new list, the list itself will be different from the original list, but the items will be shallow copies.
About your last question - as I already said, it's redundant. Remove the initialization at the beginning. You're creating an object, never use it and leave it for garbage collection. What you can do to avoid calling this in every constructor is something like this:
public DigraphNode() {
links = new ArrayList<DigraphNode<T> >();
}
And have other constructors call this constructor, for example:
public DigraphNode(T val) {
this();
this.data = val;
}
Upvoted all helpful answers, but I am answering my own question below which shows the updated code. I wanted to see how someone would implement a copy for a generic but no one posted code for that so I rolled my own. See below my answer.
import java.lang.reflect.*;
import java.util.*;
class MissingDigraphNodeException extends Exception
{
private static final long serialVersionUID = 1000L;
public MissingDigraphNodeException(String message)
{
super(message);
}
}
class CopyException extends Exception
{
private static final long serialVersionUID = 2000L;
public CopyException(String message)
{
super(message);
}
}
class DigraphNode<T>
{
Integer id;
T data;
ArrayList<DigraphNode<T> > links;
public DigraphNode(Integer i)
{
id = i;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(Integer i, T d)
{
id = i; data = d;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(DigraphNode<T> other)
{
try
{
this.data = copy(other.data);
}
catch (CopyException e)
{
e.printStackTrace();
}
this.links=other.getLinks();
this.id = new Integer(other.id);
}
// is there a better way to copy a generic?
#SuppressWarnings("unchecked")
public T copy( T source ) throws CopyException
{
Class<?> clzz = source.getClass();
Method meth;
Object dupl = null;
try {
meth = clzz.getMethod("clone", new Class[0]);
dupl = meth.invoke(source, new Object[0]);
} catch (Exception e)
{
e.printStackTrace();
throw new CopyException("Error: Copying Generic of T");
}
return (T) dupl;
}
public void setData (T d ) { data = d; }
public void addLink (DigraphNode<T> n) { links.add(n); }
public void addLinks (ArrayList<DigraphNode<T> > ns) { links.addAll(ns); }
public ArrayList<DigraphNode<T> > getLinks()
{
// return a new copy of the list
ArrayList<DigraphNode<T> > l = new ArrayList<DigraphNode<T> >();
for ( DigraphNode<T> i : links )
{
i.links.add(new DigraphNode<T>(i)); // use copy constructor
}
return l;
}
public void printNode()
{
System.out.print("Id: " + id + " links: ");
for ( DigraphNode<T> i : links )
{
System.out.print(i.id + " ");
}
System.out.println();
}
}