Accessing HashMap through a singleton - java

I have a Record class which extends a DoctorRecord class. I want threads to store these records in a hash map which I create as a singleton. My problem is every time a thread adds a record to the hash map and I try to print it's size in the main method (once all the threads have finished executing), I always get a size of 0, as if no modifications were made. However, when I print the size of the map within the method adding the records, it shows the correct size. I'm assuming it's an issue with a pass-by-value mechanic but I can't seem to correct the problem.
Hash Map singleton class:
public class MtlHashMap {
private static HashMap<Character, ArrayList<Record>> hmMtl = new HashMap<Character, ArrayList<Record>>();
public static HashMap<Character, ArrayList<Record>> getInstance(){
return hmMtl;
}
}
Thread method being called inside the overridden run() method (The hash map contains one list for every letter of the alphabet)
public synchronized void createDRecord(String firstName, String lastName, String address, long phone, String specialization, String location){
System.out.println("Create D Record");
DoctorRecord d1 = new DoctorRecord(firstName, lastName, address, phone, specialization, location);
hm = MtlHashMap.getInstance();
Character ch = lastName.toLowerCase().charAt(0);
ArrayList<Record> list = (ArrayList<Record>) hm.get(ch);
if(list == null){
System.out.println("Create list");
list = new ArrayList<Record>();
}
list.add(d1);
System.out.println("Size of list " + ch + " is " + list.size());
hm.put(ch,list);
System.out.println("Size of " + location + "hash map is " + hm.size());
}
Main
public class Main {
public static void main(String[] args) throws InterruptedException{
System.out.println("Main");
ManagerClient m1 = new ManagerClient("mtl");
ManagerClient m2 = new ManagerClient("mtl");
ManagerClient m3 = new ManagerClient("mtl");
ManagerClient m4 = new ManagerClient("mtl");
//Create Doctor Record
m1.run("Joana", "Sam", "272 Montpellier", 1231, "surgeon", "mtl");
m2.run("Joana", "Sam", "34 Lake", 1231, "surgeon", "mtl");
m4.run("Joana", "Sam", "34 Lake", 1231, "surgeon", "mtl");
m1.join();
m2.join();
m4.join();
System.out.println("Size of MTL hash map is: " + MtlHashMap.getInstance().size());
System.out.println("Size of LVL hash map is: " + LvlHashMap.getInstance().size());
System.out.println("Size of DDO hash map is: " + DdoHashMap.getInstance().size());
Manager Client Class
public class ManagerClient extends Thread{
private String location;
private String id;
private static int managerIdCounter = 1000; //Maintains unique global IDs
public ManagerClient(String location){
this.location = location.toLowerCase();
this.id = location.toLowerCase()+managerIdCounter++;
}
public String getLocation(){
return (this.location).toLowerCase();
}
public String getmId(){
return this.id;
}
//Different run method overloads for each of the four methods needed,
//with the appropriate server being called using the locateServer() method
//Default run method never used, but must be overridden anyway
public void run(){
System.out.println("This should never appear");
}
//Create Doctor Record (5 String and 1 long argument) SYNCHRONIZE THIS FOR SAFE RUNNING
#SuppressWarnings("deprecation")
public synchronized void run(String firstName, String lastName, String address, long phone, String specialization, String location){
System.out.println("Manager " + this.getmId() + " creates a D record");
try{
System.setSecurityManager(new RMISecurityManager());
String path = "rmi://localhost:2020/"+getLocation();
ClinicServerInterface server = (ClinicServerInterface)Naming.lookup(path);
server.createDRecord(firstName, lastName, address, phone, specialization, location);
}catch(Exception e){
//e.printStackTrace();
}
}
//Create Nurse Record (6 String arguments)
public synchronized void run(String firstName, String lastName, String designation, String status, String statusDate){
System.out.println("Manager " + this.getmId() + " creates a N record");
try{
System.setSecurityManager(new RMISecurityManager());
String path = "rmi://localhost:2020/"+getLocation();
ClinicServerInterface server = (ClinicServerInterface)Naming.lookup(path);
server.createNRecord(firstName, lastName, designation, status, statusDate, getLocation());
}catch(Exception e){
//e.printStackTrace();
}
}
//Get Record Counts (1 int argument)
public void run(int type){
String location = this.location;
}
//Edit Record (3 String arguments)
public void run(String recrodID, String fieldName, String newValue){
String location = this.location;
}
}

I don't know what's up with your hash map, but your program does not create any threads. Your main() routine does this:
public static void main(String[] args) throws InterruptedException {
...
ManagerClient m1 = new ManagerClient("mtl");
...
m1.run("Joana", "Sam", "272 Montpellier", 1231, "surgeon", "mtl");
...
m1.join();
...
}
That does not create a thread. That creates a ManagerClient object, and a ManagerClient object is a kind of Thread object; but a Thread is not a thread.
A thread is an operating system object that executes your code, and a Thread object is a Java object that your program uses to create an manage the life cycle of a thread. The thread will not be created until your program calls m1.start().
If you change your program to call m1.start(), here is what will happen: Your program will print This should never appear.
That's because your ManagerClient class overrides Thread.run() as follows:
//Default run method never used, but must be overridden anyway
public void run(){
System.out.println("This should never appear");
}
Your ManagerClient class also defines some other methods named "run". E.g.:
public synchronized void run(String firstName, String lastName, String address, long phone, String specialization, String location)
But that is a different method. If your program calls m1.start() to start the new thread, the new thread will call m1.run() and NOT m1.run("Joana", "Sam", "272 Montpellier", ...).
There's nothing you can do to change that. It's just how Thread.start() works.
The normal way to pass arguments to a thread that you explicitly create and start like that is to pass them through the constructor. E.g.;
ManagerClient m1 = new ManagerClient("Joana", "Sam", "272 Montpillier", ...);
m1.start();
But you might want to reconsider creating and starting threads in that way.
Your run(...) methods each just do one thing and then return. A thread dies when it's run() method returns. Creating and killing threads to perform simple tasks is a Bad Idea. Not that it will cause any harm in a toy program like your assignment, but in real-world software, the good idea that you should be using instead is called a thread pool.
You can learn about thread pools by reading up on ExecutorService, and ThreadPoolExecutor, and Executors.newFixedThreadPool(). And, by checking out the Java Concurrency Tutorial (http://docs.oracle.com/javase/tutorial/essential/concurrency/).

As it says in the Javadoc of HashMap:
Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.
But, he protests, the method is synchronized. Well, yes, it is, but not in a useful way.
If public synchronized void createDRecord(...) is a method inside the ManagerClient class, then the monitor on which you are synchronizing is the ManagerClient instance - and you have 4 of those. So whilst monitors are being acquired and released, nothing else is contending them, so it is like the synchronization is not there.
You should either use a synchronized block inside the method to lock on the hash map itself:
public void createDRecord(...) {
HashMap<Character, ArrayList<Record>> hm = MtlHashMap.getInstance();
synchronized (hm) {
// Mutually exclusive access to hm goes here.
}
}
or use a ConcurrentHashMap, like #MickMnemonic suggested in his comment.
You should also make the static hash map final, in order to guarantee that its initialized value is visible in all threads:
private static final HashMap<Character, ArrayList<Record>> hmMtl = new HashMap<>();
^

Related

java - concurrent updates to multiple objects

I am new in Java concurrency, I have a class holding data (doubles in the sample code below) that should be accessed with a get (like a Map), but with data stored internally in a array for performance reasons.
This run in a multithreaded environment and this index must be updated sometimes.
public class ConcurrencySampleCode {
private static Object lock = new Object();
private Map<String, Integer> map = ...
private double[] array = ...
public Double get(String id) {
synchronized (lock) {
Integer i = map.get(id);
if (i == null) {
return null;
}
return array[i];
}
}
public void update() {
Map<String, Integer> tmpMap = updateMap(...);
double[] tmpArray = updateArray(...);
synchronized (lock) { // should be atomic
map = tmpMap;
array = tmpArray;
}
}
}
I am not sure whether this code is correct or not? Also, is the synchronized keyword needed in the get function ?
Is there a better way of doing this ?
Thanks for your help
There's nothing wrong with your code, but you will need to use the volatile keyword on the map and the array to ensure all threads see the updated values immediately, and I'm not sure you want the lock to be static.
As an alternative you may want to check out the java.util.concurrent.atomic package. It has some handy thread-safe variable. For example you could move your map and array into their own class, then use the AtomicReference to store the object.
public class ConcurrencySampleCode {
private AtomicReference<DoubleMap> atomicMap = new AtomicReference(new DoubleMap());
//Inner class used to hold the map and array pair
public class DoubleMap {
private Map<String, Integer> map = ...
private double[] array = ...
}
public Double get(String id) {
DoubleMap map = atomicMap.get();
...
}
public void update() {
Map<String, Integer> tmpMap = updateMap(...);
double[] tmpArray = updateArray(...);
DoubleMap newMap = new DoubleMap(tmpMap, tmpArray);
atomicMap.set(newMap);
}
}
There is a lot going on in concurrent programming, but for instance your update() method is faulty. In the current state multiple Threads can call ConcurrencySampleCode.update() and every each one of them will initiate both update calls inside the body before the synchronization kicks in. This means that after the round-robin turnover the last Thread with the update call will not have the changes from the previous update calls in the newly update map and array.
Long story, try to use and understand the ConcurrentHashMap

Java cross thread / cross object Map sharing + generics

Good evening Java wizards,
I am fairly new to Java, and would like to be educated on the mistake I am not able to resolve after some hours of research.
Assume a program that has the main thread with some variables that could dynamically read/lookup value in a Map of values. This Map is shared by threads and objects accross the application.
There would be one or more separate threads updating the Map with values thus the map will be synchronized - I am considering ConcurrentHashMap.
When the reading thread arrives to one of the variables with the dynamic values it will reach in to the cross-thread shared Map and retreive its latest value against its key.
I have some prototype code here - it compliles and seam to be running as expected. However it is set to work only with a String variable and values.
Here is the code:
<code>
/*
* Cross thread / cross object shared Map
* some threads update the map
* other threads read the map for most current values (updated by other threads)
* associated with the provided key
*/
public class CrossThreadUpdatableValues {
private static final Map<Integer, String> list = new ConcurrentHashMap<>();
// return the last updated value
// from the map
public static String getValue(Integer key) {
return list.get(key);
}
// update/write the passed in value in to the map
// (in to the element having the given key)
public static void setValue(Integer key, String ev) {
list.put(key, ev);
}
}
/*
* Thread 1
* 10 loops that update the cross thread / cross object shared Map
* with unique values
*/
public class Thread1 extends Thread {
private final int delay;
private final int threadNum = 1;
Thread1(int delay) {
this.delay = delay;
}
public void run(){
for (int i=0;i<10;i++) {
String v1 = threadNum + "-AAA"; Integer key1 = 1;
String v2 = threadNum + "-BBB"; Integer key2 = 2;
String v3 = threadNum + "-CCC"; Integer key3 = 3;
CrossThreadUpdatableValues.setValue(key1, v1);
CrossThreadUpdatableValues.setValue(key2, v2);
CrossThreadUpdatableValues.setValue(key3, v3);
System.out.println("Map values updated by Thread " + threadNum + ", loop " + i);
try {
Thread.sleep(this.delay);
} catch (InterruptedException ex) {
Logger.getLogger(Thread2.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
/*
* Thread 2 (similar to Thread 1)
* 10 loops that update the cross thread / cross object shared Map
* with unique values
*/
public class Thread2 extends Thread {
private final int delay;
private final int threadNum = 2;
Thread2(int delay) {
this.delay = delay;
}
public void run(){
for (int i=0;i<10;i++) {
String v1 = threadNum + "-XXX"; Integer key1 = 1;
String v2 = threadNum + "-YYY"; Integer key2 = 2;
String v3 = threadNum + "-ZZZ"; Integer key3 = 3;
CrossThreadUpdatableValues.setValue(key1, v1);
CrossThreadUpdatableValues.setValue(key2, v2);
CrossThreadUpdatableValues.setValue(key3, v3);
System.out.println("Map values updated by Thread " + threadNum + ", loop " + i);
try {
Thread.sleep(this.delay);
} catch (InterruptedException ex) {
Logger.getLogger(Thread2.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
/*
* Reading thread -
* 20 loops that read the cross thread / crooss object shared Map
* for the most current values updated by other threads in various intervals
*/
public class ThreadRead extends Thread {
private final int delay;
private final int threadNum = 0;
ThreadRead(int delay) {
this.delay = delay;
}
public void run(){
Integer key1 = 1;
Integer key2 = 2;
Integer key3 = 3;
for (int i=0;i<20;i++) {
String v1 = CrossThreadUpdatableValues.getValue(key1);
String v2 = CrossThreadUpdatableValues.getValue(key1);
String v3 = CrossThreadUpdatableValues.getValue(key1);
System.out.println(" - - - Map values read by (reading) thread " + threadNum + ", loop " + i + "; v1 = " + v2 + "; v1 = " + v2 + "; v3 = " + v3);
try {
Thread.sleep(this.delay);
} catch (InterruptedException ex) {
Logger.getLogger(Thread2.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
/**
*
* Main test class - start of test run
*/
public class Test_Main {
public static void main(String[] args) {
// start thread that populates the shared Map with unique values
// in 5 second intervals (10x)
Thread1 thread1 = new Thread1(5000);
thread1.start();
// start thread that populates the shared Map with unique values
// in 10 second intervals (10x)
Thread2 thread2 = new Thread2(10000);
thread2.start();
// start thread that reads the shared Map of unique values
// - the latest updates from any previous thread
// in 5 second intervals (20x)
ThreadRead threadRead = new ThreadRead(5000);
threadRead.start();
}
}
</code>
These dynamic variables will naturally be of different types (Integers, Strings, etc.), so I am considering using generics, BUT that gives me the uneducated headache. As the Map needs to be shared between all involved classes and threads, it needs to be declared static and Java won't permit the use of generics on this static Map.
Here is the modification of above class CrossThreadUpdatableValues using generics - that will NOT work but a hint what I am trying to achieve:
<code>
/*
* Cross thread / crooss object shared Map
* some threads update the map
* other threads read the map for most current values (udated by other threads)
* associated with the provided key
*/
public class CrossThreadUpdatableValues<K, V> {
private static final Map<K, V> list = new ConcurrentHashMap<>();
// return the last updated value
// from the map
public static V getValue(K key) {
return list.get(key);
}
// update/write the passed in value in to the map
// (in to the element having the given key)
public static void setValue(K key, V v) {
list.put(key, v);
}
}
</code>
I would appreciate your input into how to approach this in a thread save manner, allow handling various types of variables (I know Object could be used instead of V but is it the right way to go?) and perhaps point out some hints or references on a solution or a better approach.
Thank you
If you want to save different types in the Map you will need to use Object, using generics will force a design where a specific map is created for each combination of <K, V>.
If you want to store in the same map differents kind of objects, you don´t need generics, declare your map as
Map <String, Object>
Otherwise, you can use an interface like this
package a;
public interface ICrossThreadUpdatableValues<K, V> {
// return the last updated value
// from the map
V getValue(K key);
// update/write the passed in value in to the map
// (in to the element having the given key)
void setValue(K key, V v);
}
And then do a concrete implementation for the desired types like this
package a;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/*
* Cross thread / crooss object shared Map
* some threads update the map
* other threads read the map for most current values (udated by other threads)
* associated with the provided key
*/
public class IntegerCrossThreadUpdatableValues implements ICrossThreadUpdatableValues<String, Integer> {
private final Map<String, Integer> list = new ConcurrentHashMap<>();
private static IntegerCrossThreadUpdatableValues instance;
private IntegerCrossThreadUpdatableValues() {
}
// return the last updated value
// from the map
public Integer getValue(String key) {
return list.get(key);
}
// update/write the passed in value in to the map
// (in to the element having the given key)
public void setValue(String key, Integer v) {
list.put(key, v);
}
public static IntegerCrossThreadUpdatableValues getInstance() {
if (instance == null) {
instance = new IntegerCrossThreadUpdatableValues();
}
return instance;
}
}
Note that the implementation defines a singleton pattern, you can´t instantiate the class outside of it and you can get always the same object calling 'getInstance'

How to avoid loop in this code

I am sending prices to customers (10000+) but below code has loop that causes delays in the process for customers waiting for calculations.
PriceVisibleForCustomer = Price + CustomerMargin
Price - changing every 300ms - sent from central store, not related to customer instance
CustomerMargn - some plus or minus amount that is resulting from customer agreement/segment/administrator decision etc. It doesnt change during customer http session, I can keep it in memory
Customer - he takes part in the process after he logs in, he should see rapidly changing prices of 8 products.
Maybe I need some more technology ? I have Spring 3/4, Java, Weblogic and i could create even separate webapp for this task for providing calculated prices.
I thought about threads in Java but 10000+ customers would mean too many threads wouldnt it ? How to change this code? Maybe I should change architecture but how?
/**
* Sends prices to customer. This method is called very often (300ms) as prices are changing in real time.
* Customer should see prices also each 300ms
* #param productId - id of a product that prices will be calculated
* #param productIdToPriceMap
* #param customerIdToMarginMap - this map is changed every time customer logs in or logs out
*/
private static void sendPricesToCustomers(Long productId,
Map<Long, BigDecimal> productIdToPriceMap,
Map<Long, BigDecimal> customerIdToMarginMap) {
//This loop is blocking last customer from receiving price until all other customers wil have theri prices calculated. I could create threads, 10000+ customers will be logged in, I cant create so much threads... can I?
for (Long customerId: customerIdToMarginMap.keySet()){
BigDecimal customerMargin = customerIdToMarginMap.get(customerId);
BigDecimal priceResult = productIdToPriceMap.get(productId).add(customerMargin);
//send priceResult to websocket
}
}
Here is a simple example of the Listener pattern, I am not sure if this approach will work for you but just throwing out some ideas ...
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.swing.Timer;
public class Demo {
public static Product[] PRODUCTS = new Product[]{
new Product("Computer", 400),
new Product("Desk", 800),
new Product("Chair", 70),
new Product("Printer", 300),
new Product("Television", 200)
};
public static void main(String[] args) throws InterruptedException {
Customer john = new Customer("John", 3);
john.addProduct(PRODUCTS[1]);
john.addProduct(PRODUCTS[2]);
john.addProduct(PRODUCTS[3]);
Customer mary = new Customer("Mary", 2);
mary.addProduct(PRODUCTS[1]);
mary.addProduct(PRODUCTS[2]);
mary.addProduct(PRODUCTS[4]);
Thread.sleep(10000);
System.exit(0);
}
}
interface IPriceListener {
public void priceChanged(Product product, int price);
}
class Customer implements IPriceListener {
String _name;
int _margin;
Vector<Product> _products = new Vector<Product>();
public Customer(String name, int margin){
_name = name;
_margin = margin;
}
public void addProduct(Product product){
_products.add(product);
product.addListener(this);
}
public void priceChanged(Product product, int price) {
System.out.println("[" + _name + "][" + _products.get(_products.indexOf(product)).getName() + "][" + price + "][" + (price + _margin) + "]");
}
}
class Product implements ActionListener {
private int _startingPrice;
private int _currentPrice;
private String _name;
private Timer _timer;
private Vector<IPriceListener> _listeners = new Vector<IPriceListener>();
public Product(String name, int price) {
_name = name;
_startingPrice = _currentPrice = price;
_timer = new Timer(300, this);
_timer.start();
}
public void addListener(IPriceListener listener) {
_listeners.add(listener);
}
public void removeListener(IPriceListener listener){
_listeners.remove(listener);
}
private void notifyListeners() {
for(IPriceListener listener : _listeners){
listener.priceChanged(this, getCurrentPrice());
}
}
public void actionPerformed(ActionEvent e) {
_currentPrice = _startingPrice + (int)(Math.random() * (5 - (-5))) + (-5);
notifyListeners();
}
public final String getName() {
return _name;
}
private synchronized final int getCurrentPrice() {
return _currentPrice;
}
}
One way to handle this is to create a single thread whose job is to consume priceResults off a queue and send them down the websocket (I'm assuming you have only one websocket). Your loop would then push priceResults onto the queue every 300ms without blocking the websocket thread. See ConcurrentLinkedQueue javadoc.
Edit:
To avoid the delay between finishing the current loop through customerIdToMarginMap and beginning to loop through the next update, here are some options:
Keep the queue concept and create a fixed thread pool where each thread pulls the next customerId/productIdToPriceMap/customerIdToMarginMapoff the queue. If you have four threads and 10,000 records, each thread will only have to process 2,500 records, thereby starting on the next 300ms data push 4 times earlier than your current implementation. Increase thread count as you find necessary for performance.
Keep my original queue concept but change the way you receive the price updates. The reason you need to loop is because you're getting pricing updates for every customer at the same time. If you can instead e.g. create a threaded listener for a group of customers that receives a customerIdToMarginMap containing only customerIds it's meant to handle, the iteration time will be significantly decreased.

How to print out all the elements of a List in Java?

I am trying to print out all the elements of a List, however it is printing the pointer of the Object rather than the value.
This is my printing code...
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
Could anyone please help me why it isn't printing the value of the elements.
The following is compact and avoids the loop in your example code (and gives you nice commas):
System.out.println(Arrays.toString(list.toArray()));
However, as others have pointed out, if you don't have sensible toString() methods implemented for the objects inside the list, you will get the object pointers (hash codes, in fact) you're observing. This is true whether they're in a list or not.
Since Java 8, List inherits a default "forEach" method which you can combine with the method reference "System.out::println" like this:
list.forEach(System.out::println);
Here is some example about getting print out the list component:
public class ListExample {
public static void main(String[] args) {
List<Model> models = new ArrayList<>();
// TODO: First create your model and add to models ArrayList, to prevent NullPointerException for trying this example
// Print the name from the list....
for(Model model : models) {
System.out.println(model.getName());
}
// Or like this...
for(int i = 0; i < models.size(); i++) {
System.out.println(models.get(i).getName());
}
}
}
class Model {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
System.out.println(list);//toString() is easy and good enough for debugging.
toString() of AbstractCollection will be clean and easy enough to do that. AbstractList is a subclass of AbstractCollection, so no need to for loop and no toArray() needed.
Returns a string representation of this collection. The string representation consists of a list of the collection's elements in the
order they are returned by its iterator, enclosed in square brackets
("[]"). Adjacent elements are separated by the characters ", " (comma
and space). Elements are converted to strings as by
String.valueOf(Object).
If you are using any custom object in your list, say Student , you need to override its toString() method(it is always good to override this method) to have a meaningful output
See the below example:
public class TestPrintElements {
public static void main(String[] args) {
//Element is String, Integer,or other primitive type
List<String> sList = new ArrayList<String>();
sList.add("string1");
sList.add("string2");
System.out.println(sList);
//Element is custom type
Student st1=new Student(15,"Tom");
Student st2=new Student(16,"Kate");
List<Student> stList=new ArrayList<Student>();
stList.add(st1);
stList.add(st2);
System.out.println(stList);
}
}
public class Student{
private int age;
private String name;
public Student(int age, String name){
this.age=age;
this.name=name;
}
#Override
public String toString(){
return "student "+name+", age:" +age;
}
}
output:
[string1, string2]
[student Tom age:15, student Kate age:16]
Use String.join()
for example:
System.out.print(String.join("\n", list));
The Java 8 Streams approach...
list.stream().forEach(System.out::println);
The objects in the list must have toString implemented for them to print something meaningful to screen.
Here's a quick test to see the differences:
public class Test {
public class T1 {
public Integer x;
}
public class T2 {
public Integer x;
#Override
public String toString() {
return x.toString();
}
}
public void run() {
T1 t1 = new T1();
t1.x = 5;
System.out.println(t1);
T2 t2 = new T2();
t2.x = 5;
System.out.println(t2);
}
public static void main(String[] args) {
new Test().run();
}
}
And when this executes, the results printed to screen are:
t1 = Test$T1#19821f
t2 = 5
Since T1 does not override the toString method, its instance t1 prints out as something that isn't very useful. On the other hand, T2 overrides toString, so we control what it prints when it is used in I/O, and we see something a little better on screen.
Or you could simply use the Apache Commons utilities:
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/ArrayUtils.html#toString-java.lang.Object-
List<MyObject> myObjects = ...
System.out.println(ArrayUtils.toString(myObjects));
Consider a List<String> stringList which can be printed in many ways using Java 8 constructs:
stringList.forEach(System.out::println); // 1) Iterable.forEach
stringList.stream().forEach(System.out::println); // 2) Stream.forEach (order maintained generally but doc does not guarantee)
stringList.stream().forEachOrdered(System.out::println); // 3) Stream.forEachOrdered (order maintained always)
stringList.parallelStream().forEach(System.out::println); // 4) Parallel version of Stream.forEach (order not maintained)
stringList.parallelStream().forEachOrdered(System.out::println); // 5) Parallel version ofStream.forEachOrdered (order maintained always)
How are these approaches different from each other?
First Approach (Iterable.forEach)-
The iterator of the collection is generally used and that is designed to be fail-fast which means it will throw ConcurrentModificationException if the underlying collection is structurally modified during the iteration. As mentioned in the doc for ArrayList:
A structural modification is any operation that adds or deletes one or
more elements, or explicitly resizes the backing array; merely setting
the value of an element is not a structural modification.
So it means for ArrayList.forEach setting the value is allowed without any issue. And in case of concurrent collection e.g. ConcurrentLinkedQueue the iterator would be weakly-consistent which means the actions passed in forEach are allowed to make even structural changes without ConcurrentModificationExceptionexception being thrown. But here the modifications might or might not be visible in that iteration.
Second Approach (Stream.forEach)-
The order is undefined. Though it may not occur for sequential streams but the specification does not guarantee it. Also the action is required to be non-interfering in nature. As mentioned in doc:
The behavior of this operation is explicitly nondeterministic. For
parallel stream pipelines, this operation does not guarantee to
respect the encounter order of the stream, as doing so would sacrifice
the benefit of parallelism.
Third Approach (Stream.forEachOrdered)-
The action would be performed in the encounter order of the stream. So whenever order matters use forEachOrdered without a second thought. As mentioned in the doc:
Performs an action for each element of this stream, in the encounter
order of the stream if the stream has a defined encounter order.
While iterating over a synchronized collection the first approach would take the collection's lock once and would hold it across all the calls to action method, but in case of streams they use collection's spliterator, which does not lock and relies on the already established rules of non-interference. In case collection backing the stream is modified during iteration a ConcurrentModificationException would be thrown or inconsistent result may occur.
Fourth Approach (Parallel Stream.forEach)-
As already mentioned no guarantee to respect the encounter order as expected in case of parallel streams. It is possible that action is performed in different thread for different elements which can never be the case with forEachOrdered.
Fifth Approach (Parallel Stream.forEachOrdered)-
The forEachOrdered will process the elements in the order specified by the source irrespective of the fact whether stream is sequential or parallel. So it makes no sense to use this with parallel streams.
I have faced similar problems. My code:
List<Integer> leaveDatesList = new ArrayList<>();
.....inserted value in list.......
Way 1: printing a list in a for loop
for(int i=0;i<leaveDatesList.size();i++){
System.out.println(leaveDatesList.get(i));
}
Way 2: printing the list in a forEach, for loop
for(Integer leave : leaveDatesList){
System.out.println(leave);
}
Way 3: printing the list in java 8
leaveDatesList.forEach(System.out::println);
You haven't specified what kind of elements the list contains, if it is a primitive data type then you can print out the elements.
But if the elements are objects then as Kshitij Mehta mentioned you need to implement (override) the method "toString" within that object - if it is not already implemented - and let it return something meaning full from within the object, example:
class Person {
private String firstName;
private String lastName;
#Override
public String toString() {
return this.firstName + " " + this.lastName;
}
}
It depends on what type of objects stored in the List, and whether it has implementation for toString() method. System.out.println(list) should print all the standard java object types (String, Long, Integer etc). In case, if we are using custom object types, then we need to override toString() method of our custom object.
Example:
class Employee {
private String name;
private long id;
#Override
public String toString() {
return "name: " + this.name() +
", id: " + this.id();
}
}
Test:
class TestPrintList {
public static void main(String[] args) {
Employee employee1 =new Employee("test1", 123);
Employee employee2 =new Employee("test2", 453);
List<Employee> employees = new ArrayList(2);
employee.add(employee1);
employee.add(employee2);
System.out.println(employees);
}
}
For a list of array of String
list.forEach(s -> System.out.println(Arrays.toString((String[]) s )));
For loop to print the content of a list :
List<String> myList = new ArrayList<String>();
myList.add("AA");
myList.add("BB");
for ( String elem : myList ) {
System.out.println("Element : "+elem);
}
Result :
Element : AA
Element : BB
If you want to print in a single line (just for information) :
String strList = String.join(", ", myList);
System.out.println("Elements : "+strList);
Result :
Elements : AA, BB
System.out.println(list); works for me.
Here is a full example:
import java.util.List;
import java.util.ArrayList;
public class HelloWorld {
public static void main(String[] args) {
final List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
System.out.println(list);
}
}
It will print [Hello, World].
list.stream().map(x -> x.getName()).forEach(System.out::println);
I wrote a dump function, which basicly prints out the public members of an object if it has not overriden toString(). One could easily expand it to call getters.
Javadoc:
Dumps an given Object to System.out, using the following rules:
If the Object is Iterable, all of its components are dumped.
If the Object or one of its superclasses overrides toString(), the "toString" is dumped
Else the method is called recursively for all public members of the Object
/**
* Dumps an given Object to System.out, using the following rules:<br>
* <ul>
* <li> If the Object is {#link Iterable}, all of its components are dumped.</li>
* <li> If the Object or one of its superclasses overrides {#link #toString()}, the "toString" is dumped</li>
* <li> Else the method is called recursively for all public members of the Object </li>
* </ul>
* #param input
* #throws Exception
*/
public static void dump(Object input) throws Exception{
dump(input, 0);
}
private static void dump(Object input, int depth) throws Exception{
if(input==null){
System.out.print("null\n"+indent(depth));
return;
}
Class<? extends Object> clazz = input.getClass();
System.out.print(clazz.getSimpleName()+" ");
if(input instanceof Iterable<?>){
for(Object o: ((Iterable<?>)input)){
System.out.print("\n"+indent(depth+1));
dump(o, depth+1);
}
}else if(clazz.getMethod("toString").getDeclaringClass().equals(Object.class)){
Field[] fields = clazz.getFields();
if(fields.length == 0){
System.out.print(input+"\n"+indent(depth));
}
System.out.print("\n"+indent(depth+1));
for(Field field: fields){
Object o = field.get(input);
String s = "|- "+field.getName()+": ";
System.out.print(s);
dump(o, depth+1);
}
}else{
System.out.print(input+"\n"+indent(depth));
}
}
private static String indent(int depth) {
StringBuilder sb = new StringBuilder();
for(int i=0; i<depth; i++)
sb.append(" ");
return sb.toString();
}
I happen to be working on this now...
List<Integer> a = Arrays.asList(1, 2, 3);
List<Integer> b = Arrays.asList(3, 4);
List<int[]> pairs = a.stream()
.flatMap(x -> b.stream().map(y -> new int[]{x, y}))
.collect(Collectors.toList());
Consumer<int[]> pretty = xs -> System.out.printf("\n(%d,%d)", xs[0], xs[1]);
pairs.forEach(pretty);
public static void main(String[] args) {
answer(10,60);
}
public static void answer(int m,int k){
AtomicInteger n = new AtomicInteger(m);
Stream<Integer> stream = Stream.generate(() -> n.incrementAndGet()).limit(k);
System.out.println(Arrays.toString(stream.toArray()));
}
try to override toString() method as you want that the element will be printend.
so the method to print can be this:
for(int i=0;i<list.size();i++){
System.out.println(list.get(i).toString());
}
Solusion of your problem for java 11 is:
String separator = ", ";
String toPrint = list.stream().map(o -> String.valueOf(o)).collect(Collectors.joining(separator));
System.out.println(toPrint);
You can try:
for 2D(or more)
System.out.println(Arrays.deepToString(list.toArray()));
for 1D
System.out.println(Arrays.toString(list.toArray()))
List<String> textList= messageList.stream()
.map(Message::getText)
.collect(Collectors.toList());
textList.stream().forEach(System.out::println);
public class Message {
String name;
String text;
public Message(String name, String text) {
this.name = name;
this.text = text;
}
public String getName() {
return name;
}
public String getText() {
return text;
}
}

load table in Java program

I have a table with 25 rows and 3-4 columns. I want to use this table once to read all data from it and store it in Java program. Since I will need data frequently throughout my life cycle of Java program, I dont want to connect to DB and execute query. How can I achieve this?
I would create a class with a member that corresponds to the data in the table.
Then I would create some data structure (a map?) by which you can acquire the data.
If you need to have 'database like' access, use an embeded database like Apache Derby. Slurp the data in once from outside, then store it in your local database which will have very responsive lookup times.
Some pseduo-code
Let this class be your binding, for example... I just made stuff up
class MyObject {
private final String key;
private final long stamp;
private final String name;
private final int other;
public MyObject(String key, long stamp, String name, int other) {
this.key = key;
this.stamp = stamp;
this.name = name;
this.other = other;
}
public String toString() {
return name + " has an other of " + other + " and a stamp of " + stamp;
}
}
Your application might look something like this
class MyApp {
Connection con = ... // connect to DB here
// work with DB
ResultSet rs = ... // query the DB for your data
Map<String, MyObject> map = new HashMap<String, MyObject>();
while(rs.next()) {
String key = rs.getString(1);
long stamp = rs.getLong(2);
String name = rs.getString(3);
int other = rs.getInteger(4);
MyObject obj = new MyObject(key,stamp,name,other);
map.put(key,obj);
}
Map<String, MyObject> safeMap = Collections.unmodifiableMap(map);
// spawn 5 threads (yes we should keep ref's to them - oh well
for(int i = 0; i < 5; i++) {
Runnable run = new SomeBackgroundProcess(i,safeMap);
Thread t = new Thread(run);
t.start();
}
}
And a background thread might look something like this
class SomeBackgroundProcess {
final int awesomeNumber;
final Map<String,MyObject> map;
SomeBackgroundProcess(int num, Map<String,MyObject> map) {
this.awesomeNumber = num;
this.map = map;
}
public void run() {
InputStream in = // some input stream, for example
while(true) {
String key = in.magic(); // somehow you acquired a key!
MyObject obj = map.get(key);
if(obj != null) Log.log(obj.toString()); // writes out all about the object it found
}
}
}
if you want to use JTable for display/edit/input/remove some data then you have to
1) first at all read tutorial (all data are allways stored in the TableModel, read this sctions too,)
2) and then go thought ton os examples here and here
3) than if you have a real question how to some..., then don't hesitage to ask question, and in the case that you want from this forum good or better answer, then you have to ... with short and runnable code that shows your issue(s)
You can look up hibernate. It will serve you good as it's used frequently in the industry. You basically provides a properties file with your db info such as server address and credentials and then you make a POJO representing your table and put some annotations on it.
you can use cache concept which holds the data till the user session is lost. Please check below link, there are many examples available google it.
cache concept

Categories

Resources