I want to make a singleton class Phone, so that it can be initializable (with number) and also concurrent-safe. So, here is what I came with:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class PhoneTest {
public static void main(String... args){
System.out.println(Phone.getInstance().getNumber());
}
static final class Phone {
private final String number;
private final static Phone instance;
static {
instance = new Phone(PhonePropertyReader.readPhoneNumber());
}
private Phone(String number) {
this.number = number;
}
public static Phone getInstance() {
if (instance == null) throw
new IllegalStateException("instance was not initialized");
return instance;
}
public String getNumber() {
return number;
}
}
static final class PhonePropertyReader {
static String readPhoneNumber() {
File file = new File("phone.properties");
String phone = "";
System.out.println(file.getAbsolutePath());
if (!file.exists()) {
return phone = "555-0-101";
}
try {
BufferedReader r = new BufferedReader(new FileReader(file));
phone = r.readLine().split("=")[1].trim();
r.close();
} catch (IOException e) {
}
return phone;
}
}
}
also I have a file phone.properties containing
phone=12345
Is it a good solution? Is it concurrent safe?
I believe that Enum still the best way to implement thread-safe singletons in java.
I would discourage you to use singletons (Check this other question)
Otherwise, your code is thread-safe since the only affectation you do is in a static {} area which is, by definition, thread safe.
Btw, why not incorporate your readPhoneNumber() method directly in your phone class ?
Related
I have this console application, but for some reason the thread's run() method doesn't want to start. The code seems long for the first time but I tried to organize it as much as I can.
The result output:
eThread starting!!
So it seems that CarManager.startFunctionalities() gets executed, but the line eThread.start() is not executed at all because the line "started" is not printed out.
Here is the sourcecode.
The main class:
package rpicar.android;
public class AndroidEmulator{
public static void main(String args[]) throws InterruptedException {
CarManager cm = new CarManager ("localhost");
}
}
CarManager:
package rpicar.android;
import rpicar.common.Direction;
import rpicar.common.EnvironmentData;
public class CarManager {
private MotorManager mManager;
private final String RPIADDRESS = "localhost";
private Thread mThread; //motor
private EnvironmentManager eManager;
private Thread eThread;
public CarManager(String rpiAddress) {
//initialize MotorManager
mManager = new MotorManager(RPIADDRESS);
//Make a thread for the Motor commands
mThread = new Thread(mManager);
//Initialize EnvironmentManager
eManager = new EnvironmentManager(RPIADDRESS);
//Makea thread for collecting EnvironmentData
eThread = new Thread (eThread);
startFunctionalities();
}
public void move(Direction d){
this.mManager.setDirection(d);
}
public EnvironmentData getCurrentEnvironmentData(){
return this.eManager.getCurrentEnvironmentData();
}
private void startFunctionalities(){
//Start MotorManager for sending movement commands when needed.
//mThread.start();
//Start EnvironmentManager to collect EnvironmentData
System.out.println("eThread starting!! ");
eThread.start();
}
}
EnvironmentManager:
package rpicar.android;
import rpicar.common.CarComponent;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import rpicar.common.EnvironmentData;
public class EnvironmentManager extends CarComponent implements Runnable{
private EnvironmentData currentEnvironmentData;
public EnvironmentManager(String rpiAddress) {
super(rpiAddress, 2176, true);
this.currentEnvironmentData = new EnvironmentData();
}
public synchronized EnvironmentData getCurrentEnvironmentData() {
return currentEnvironmentData;
}
public synchronized void setCurrentEnvironmentData(EnvironmentData currentEnvironmentData) {
this.currentEnvironmentData = currentEnvironmentData;
}
#Override
public void run() {
System.out.println("eThread started!! ");
super.connect();
while(true){
try {
this.setCurrentEnvironmentData((EnvironmentData) super.in.readObject());
} catch (IOException ex) {
super.connect();
} catch (ClassNotFoundException ex) {
Logger.getLogger(EnvironmentManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
When you create your instance of eThread, you accidentally pass the thread itself to the constructor (or according to the order of the operations, you pass null).
You should pass eManager to the constructor instead.
eThread = new Thread (eThread);
Would become
eThread = new Thread (eManager);
You can protect yourself in the future from this mistake by making the eThread a final field, so you cannot use it before you declare it.
Suppose I have a Crypto Class.
public class Crypto{
// This method returns the instance of Crypto class for the key.
// If instance for key hasn't been created a new instance is created.
// If already created for key the same instance is returned.
public static Crypto getInstance(String key){
}
}
How do I implement this pattern? I mean this is singleton design pattern but different instances for different keys and where do I save the instance?
I think you can use a map :
Class Crypto{
Map<String,Crypto> map = new HashMap<String,Crypto>();
private Crypto(){
}
public static Crypto getInstance(String key){
if(map.contains(key)){
return map.get(key);
}
else{
// switch on the key and create your Cryptos
map.put(key,new Crypto();
}
return map.get(key);
}
}
Sounds like you want the multiton pattern. This is a simple example for an implicit synchronized version:
import java.util.HashMap;
import java.util.Map;
public class Multiton {
private static final class MultitonHolder {
static final Map<String, Multiton> INSTANCES = new HashMap<>();
static {
INSTANCES.put("key-1", new Multiton());
INSTANCES.put("key-2", new Multiton());
INSTANCES.put("key-3", new Multiton());
INSTANCES.put("key-4", new Multiton());
INSTANCES.put("key-5", new Multiton());
}
}
private Multiton() {}
public static Multiton getInstance(final String key) {
return MultitonHolder.INSTANCES.get(key);
}
}
Example with additional fields:
import java.util.HashMap;
import java.util.Map;
public class Multiton {
private static class MultitonHolder {
static final Map<String, Multiton> INSTANCES = new HashMap<>();
static {
INSTANCES.put("key-1", new Multiton(1));
INSTANCES.put("key-2", new Multiton(2));
final Multiton multiton3 = new Multiton(3);
multiton3.setAnotherField(3);
INSTANCES.put("key-3", multiton3);
final Multiton multiton4 = new Multiton(4);
multiton3.setAnotherField(4);
INSTANCES.put("key-4", multiton4);
}
}
private final int someField;
private int anotherField;
private Multiton(final int someField) {
this.someField = someField;
}
public static Multiton getInstance(final String key) {
return MultitonHolder.INSTANCES.get(key);
}
public int getSomeField() {
return someField;
}
private void setAnotherField(final int anotherField) {
this.anotherField = anotherField;
}
public int getAnotherField() {
return anotherField;
}
}
Similar with the above examples
public class Crypto {
private ArrayList<String> keyList = new ArrayList<String>();
private static Crypto uniqInstance;
private Crypto() {
}
public static Crypto getInstance(){
if (uniqInstance==null){
synchronized (Crypto.class){
if(uniqInstance==null){
uniqInstance = new Crypto();
}
}
}
return uniqInstance;
}
public void addKey(String key){
this.keyList.add(key);
}
public String toString(){
String s="";
for(String str:keyList){
s+=str+" ";
}
return s;
}
}
I tested it with the following:
public class CryptoApp {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Crypto crypto;
crypto = Crypto.getInstance();
crypto.addKey("my123");
crypto.addKey("my456");
System.out.println(crypto);
Crypto crypto2;
crypto2 = Crypto.getInstance();crypto2.addKey("my789");System.out.println(crypto2);
}
}
I am new to java technology.So i was going through SequenceInputStreamI tried below code,but i am not able to find the exact problem, kindly some one help
public class SequenceInput {
public static void main(String[] args) throws IOException {
Enumeration e=new MyEnum();
SequenceInputStream sin=new SequenceInputStream(e);
DataInputStream din=new DataInputStream(sin);
String s="";
while(null !=s) {
s=din.readLine();
if(null !=s) {
System.out.println(s);
}
}
din.close();
// new Vector().elements();
}
//Enumeration Class
public class MyEnum implements Enumeration{
InputStream in[];
int i=0;
public MyEnum(){
try {
in=new InputStream[] {new FileInputStream("src/a1.txt"),new FileInputStream("src/a2.txt"),new FileInputStream("src/a3.txt"),new FileInputStream("src/a4.txt")};
}
catch(Exception e) {
}
}
#Override
public boolean hasMoreElements() {
if(in.length<=4) {
return true;
}
else
return false;
}
#Override
public Object nextElement() {
return in[i++];
}
}
}
In this line Enumeration e=new MyEnum(); it is showing
- No enclosing instance of type SequenceInput is accessible. Must qualify the
allocation with an enclosing instance of type SequenceInput (e.g. x.new A() where x is an
instance of SequenceInput).
I am not getting the exact problem.
Else i have used new Vector().add() and it was working fine with sequenceInputStream. Wanted to know about above code..Where am i making mistake.
Thanks in advance.
To access your class without needed an enclosing instance, you have to make it static
public static class MyEnum implements Enumeration {
...
}
Check this
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Enumeration;
public class SequenceInput {
public static void main(String[] args) throws IOException {
Enumeration e=new MyEnum();
SequenceInputStream sin=new SequenceInputStream(e);
DataInputStream din=new DataInputStream(sin);
String s="";
while(null !=s) {
s=din.readLine();
if(null !=s) {
System.out.println(s);
}
}
din.close();
// new Vector().elements();
}
//Enumeration Class
public static class MyEnum implements Enumeration{
InputStream in[];
int i=0;
public MyEnum(){
try {
in=new InputStream[] {new FileInputStream("src/a1.txt"),new FileInputStream("src/a2.txt"),new FileInputStream("src/a3.txt"),new FileInputStream("src/a4.txt")};
}
catch(Exception e) {
}
}
#Override
public boolean hasMoreElements() {
if(in.length<=4) {
return true;
}
else
return false;
}
#Override
public Object nextElement() {
return in[i++];
}
}
}
I would like to use db4o and I`m learning this using in youtube.com tutorial. Unfortunately I'm not able to find mistake in my code. I would like to know why I have got there error? I added all important library.
Code important class:
package data;
import com.db4o.*;
import com.db4o.config.EmbeddedConfiguration;
public class DataConnection {
private static DataConnection INSTANCE =null;
private final String PATH = "test.db4o";
private static ObjectContainer db;
private DataConnection(){}
private synchronized static void createInstance(){
if (INSTANCE ==null){
INSTANCE = new DataConnection();
INSTANCE.performConnection();
}}
public void performConnection() {
EmbeddedConfiguration config = Db4oEmbedded.newConfiguration();
db = Db4oEmbedded.openFile(config, PATH);
}
public static ObjectContainer getInstance() {
if(INSTANCE == null) createInstance();
return db;
}
public static void closeConnection() {
try{
db.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Here is this tutorial (important thing 5:44):
http://www.youtube.com/watch?v=dcNfkED53to
Try replacing
new DataConnection.getInstance()
with
DataConnection.getInstance()
The keyword new is only used when creating a new object. Here you are calling a static method.
I have been give a jar file to use that has a static inner class inside of another static inner class:
package externalJarFile;
public class Job
{
public static class GlobalVars
{
private List<Job.GlobalVars.Variable> variables;
public List<Job.GlobalVars.Variable> getVariable()
{
if (this.variables == null) {
this.variables = new ArrayList<Job.GlobalVars.Variable>();
}
return this.variables;
}
public static class Variable
{
String name;
String value;
public String getName() { return name; }
public void setName( String name ) { this.name = name; }
public String getValue() { return value; }
public void setValue( String value) { this.value= value; }
}
}
}
The problem I'm having is that I need to populate the "Job.GlobalVars" list, but I can't figure out how to reference the "Variables" type. Whenever I add:
import externalJarFile.Job.GlobalVars.Variable;
I get a compilation error that the type "externalJarFile.Job.GlobalVars.Variable" cannot be referenced. How can I create a new "Variable" instance to add to the "GlobalVars.getVariable()" list?
Here's a snippet that I tried (but didn't work):
Job.GlobalVars vars = new Job.GlobalVars();
Job.GlobalVars.Variable v = new Job.GlobalVars.Variable();
[Edited for clarity]
[UPDATE]
Ok, this is kinda weird. If I take the code from the original project and directly import it into mine, I'm able to reference the inner-inner-class. However, when I reference it when it's packaged inside of a jar file, it fails. MTK...
You forgot a space:
Job.GlobalVars vars = new Job.GlobalVars();
^
This works fine for me:
Job.GlobalVars.Variable var = new Job.GlobalVars.Variable();
var.setName("MByD");
Class job:
package mypackage;
import java.util.ArrayList;
import java.util.List;
public class Job {
public static class GlobalVars
{
private List<Variable> variables;
public List<Variable> getVariable()
{
if (this.variables == null) {
this.variables = new ArrayList<Variable>();
}
return this.variables;
}
public static class Variable
{
String name;
String value;
public String getName() { return name; }
public void setName( String name ) { this.name = name; }
public String getValue() { return value; }
public void setValue( String value) { this.value= value; }
}
}
}
Other class using GlobalVars and Variable. Import works very good.
package mypackage;
import mypackage.Job.GlobalVars;
import mypackage.Job.GlobalVars.Variable;
public class RunIt {
public static void main(String[] args) {
GlobalVars vars = new GlobalVars();
Variable v = new Variable();
}
}
No need to import anything. You should be able to just refer to your inner class by its name, "Variable", from the "Job" class:
private List<Variable> variables;
public List<Variable> getVariable()
They way you had stated above is correct. You should check to ensure that the jar file is in your classpath as that would definitely cause the import to fail and subsequently all future declarations.
import mypackage.Job.GlobalVars.Variable;
...
Variable v = new Variable();