I am creating a prison system where I need to store the names and because I need to print out all the prisoner information in one of the methods. I want to make it remember and store information such as name, id and crimes etc. How can I go about doing this?
About the posted answers, I don't think it needs to be something that complicated because I haven't learnt any of this for the assignment. All I want is for my program to print out the prisoner ID, name, starting and ending date, crime with just one run of the program after I am prompted to enter the information.
INPUT/OUTPUT
New Prisoner
Enter Name:
Enter crime:
Enter Name:
Enter crime:
Prisoner information
(name) has committed (crime)
(name) has committed (crime)
The short answer is "a database."
Your question indicates that the following could be overwhelming but it could be worth some effort to read about "Macto," an end-to-end sample Ayende Rahein has been writing about.
You haven't made particularly clear in your question as to whether you just want to store the prisoner details in memory while the program is running, or if you want to persist the prisoners to disk, so that you can close your program and load them again next time you start it.
If its the former, you can just store the prisoners in an array or a list. For example assuming your prisoner class looks something like this:
public class Prisoner {
private String name;
private String crime;
public Prisoner(String name, String crime) {
this.name = name;
this.crime = crime;
}
public String getName() {
return name;
}
public String getCrime() {
return crime;
}
}
You can then store the prisoners in a list...
List<Prisoner> prisoners = new LinkedList<Prisoner>();
prisoners.add(new Prisoner("Bob", "Murder"));
prisoners.add(new Prisoner("John", "Fraud"));
...and then iterate over the list and print the details out...
for(Prisoner p : prisoners) {
System.out.println(p.getName() + " committed " + p.getCrime());
}
If you're looking for a way to persist the prisoner details between runs of the program there are a number of possible approaches, most of which have already mentioned. In most cases a database is the best solution for storing records with JDBC being the simplest way of connecting to and interacting with a database.
For simplicity however, I would suggest storing the details in a CSV (comma separated value) file. A CSV file is simply a plain text file that stores each record on a new line, with a comma separating each field. For example:
Bob, Murder
John, Fraud
There are a number of CSV reading libraries around (see here), however its quite easy to read + write to a CSV file with no external libraries. Below is an example:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
public class PrisonerStore {
/**
* The file the prisoners are stored in
*/
private File store;
public PrisonerStore(File store) {
this.store = store;
}
/**
* Saves the specified prisoner to the file
* #param prisoner
*/
public void savePrisoner(Prisoner prisoner) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(store, true));
writer.write(prisoner.getName() + "," + prisoner.getCrime());
writer.newLine();
writer.close();
}
/**
* Reads all prisoners from the file and returns a list of prisoners
* #return
*/
public List<Prisoner> loadPrisoners() throws IOException{
List<Prisoner> prisoners = new LinkedList<Prisoner>();
BufferedReader br = new BufferedReader(new FileReader(store));
//Read each line of the file and create a Prisoner object from it
String line = null;
while((line = br.readLine()) != null) {
String[] parts = line.split(",");
Prisoner p = new Prisoner(parts[0], parts[1]);
prisoners.add(p);
}
br.close();
return prisoners;
}
}
In your code you can then do something like the following:
PrisonerStore store = new PrisonerStore(new File("C:\\myFile.csv"));
Prisoner p1 = new Prisoner("Bob", "Murder");
Prisoner p2 = new Prisoner("John", "Fraud");
try {
store.savePrisoner(p1);
store.savePrisoner(p2);
List<Prisoner> list = store.loadPrisoners();
for(Prisoner p : list) {
System.out.println(p.getName() + " committed " + p.getCrime());
}
} catch (IOException e) {
System.out.println("Error storing prisoners");
}
If these informations need to persist beyond the life of the VM, you'll have to write them on a physical storage (actually, persistence is the mechanism that allow to pass from a physical storage to an in memory representation).
There are several solutions for this purpose:
Java Object Serialization
A prevalent system with a library like Prevalayer
XML serialization with a library like XStream
A database (relational or not)
Serialization is Java built-in persistence mechanism but is very fragile. Prevalence is based on serialization but I have no experience with it and I'm not sure it solves the weakness of serialization. XML serialization is interesting and quite fast to put in place, especially with a library like XSteam. Finally, a database is the most "standard" solution but introduces some complexity. Depending on your needs, use straight JDBC or JPA for the data access.
My advice: If you don't need a database, go for XML serialization and use XStream. See the Two Minute Tutorial on XStream web site to get started. If you don't need persistence at all (beyond the life of the VM), just store the prisoners in a List.
Where do you want store information ?
If you want store information in program (memory), you can use a static member variables,like this:
// Prisoner.java
class Prisoner {
public String Name;
public int Age;
}
// Prisoners.java
class Prisoners {
public static Prisoner[] GetAll() {
Prisoner[] _data;
// Load from database to _data;
return _data;
}
}
// test.java
class test() {
public static void out() {
System.out.println(main.allPrisoner.getLength());
}
}
// main.java
public class main{
public static Prisoner[] allPrisoner;
public static main(String args[]){
public allPrisoner = Prisoners.GetAll();
// From now all prisoners will be stored in program memory until you close it
}
}
So, If you are Web Development, you can use WebCache
If you are looking to use a database, one place to start is with Hibernate. Its a java library that can provide java object to relational database table mapping.
If you want to persist to a file system using an object serialization routine, I'd recommend XStream to serialize XML or JSON text.
Based on the added text to the question, I'd recommend having a look at XStream just because it is so simple to use if you need to get the data structures to a file on the disk. However, more basically...
You probably just need to make a Prisoner class that has the stuff you need Prisoner to have, such as a name, identifier, etc, etc.
public class Prisoner
{
private String name;
private int identifier;
public Prisoner(String aName, int anId)
{
name = aName;
identifier = anId;
}
public String toString()
{
return "Prisoner[ name = " + name + ", id = " + identifier + " ]";
}
}
Then you can store them in a Map<String, Prisoner> to make finding them easier.
Map<String, Prisoner> prisonMap = new HashMap<String, Prisoner>();
To enter them in from the command line, you'll probably need to use System.in
Sun provides a good tutorial for it.
If you just want to print them back out on the command line, you'll iterate over the Map's keyset and get each value or just iterate over the values and just use System.out.println() to print them out.
for(Prisoner p : prisonMap.values())
{
System.out.println(p);
}
Or, use XStream to print out the XML to file or the System.out stream.
Related
So in my java class, we need to read this file and somehow converts its content into an object
import java.util.Scanner;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Calendar {
public Appointment[] appointments;
Calendar()
{
appointments = null;
}
Calendar(int capacity, String filename)
{
Appointment[] appointments = new Appointment[capacity];
//you can see that appointments is an Appointment object
readCalendarFromFile(filename);}
private void readCalendarFromFile(String fileName){
Scanner fileRead = null;
try
{
fileRead = new Scanner(new FileInputStream("appointments.txt"));
for(int r = 0; r < 30; r++)
appointments[r]= fileRead.nextLine(); ----> This is where I am getting my error from as I cannot convert String into an object. Is there a way that I can pass this
fileRead.close();
}
catch (FileNotFoundException fe)
{
fe.printStackTrace();
System.err.println("Unable to open the file " + fileName + " for reading.");
}
}
}
Is there any way that I can convert filetext into an object or do I have to do something else with it? I have to make an appointment an object so I can't change it into anything else sadly.
You have to have a class Appointment somewhere, and what you are trying to do is add an object of the type Appointment to the array appointments, based on the info you get from the text file, right?
So, you have your for loop that reads every line from the text file, and then you need to create instances of Appointment for each line.
The class Appointment has some kind of constructor, that you need to call to create a new object (read: "a new instance") from it.
Let's assume it looks like this:
public Appointment(String title, String time, String location) {
this.title = title;
this.time = time;
this.location = location;
}
Let's also assume that every line in the file appointments.txt is formatted in the following way:
<Title>, <Time>, <Location>
Which means, that you would have to parse the line that you read from the file by splitting it (the delimiter in this case would be the ",". Just do a quick research on the internet on how to split Strings in Java, it's pretty easy actually.
When you have all the bits of information in separate variables, you have to call the constructor of Appointment, to create a new appointment that you can then add to your array. Assuming that you have three Strings with the title, the time and the location of the appointment (or whatever info you have in the text file), this would look like this:
try{
fileRead = new Scanner(new FileInputStream("appointments.txt"));
int counter = 0;
while(fileRead.hasNext()) {
String lineRead = fileRead.nextLine();
// here comes the parsing of the line into three String variables
appointments[counter] = new Appointment(title, time, location);
fileRead.close();
}
} catch(FileNotFoundException ex) {
// Do some exception handling in here, or just print the stacktrace
}
The line I want you to pay the most attention to is the Line, where it says new Appointment(title, time, location). The difference between this and the code that you posted is, that here I create a new object of the type Appointment, that corresponds with the type of the array you created earlier, in the line Appointment[] appointments = new Appointment[capacity].
You tried to directly add a String to the array, although you declared an array of the type Appointment, not of the type String.
You should read up on the topic of objects in Java in general, and what constructors are, what they do and how you use them.
For example, this topic gets explained really well and exhaustive in the official Java tutorials from Oracle (the company that develops the Java Language). I linked you the specific section that talks about constructors, but I would suggest that you read at least the whole chapter and everything before it that helps you understand what they actually talk about.
Hope this helps :)
I have this piece of data (this is just one part of one line of the whole file):
000000055555444444******4444 YY
I implemented this CSV config file to be able to read each part of the data and parse it:
128-12,140-22,YY
The first pair (128-12) represent at what position in the line to start reading and then the amount of characters to read, that first pair is for the account number.
The second pair if for the card number.
And the thir parameter is for the registry name.
Anyways, what I do is String.split(","), and then assign the array[0] as the account number and so on.
But I want to change that CSV config file to a Property file, but I'm not sure of how to implement that solution, if I use a Properties file I'd have to add a bunch of if/then in order to properly map my values, here's what I'm thinking of doing:
Property cfg = new Property();
cfg.put("fieldName", "accountNumber");
cfg.put("startPosition", "128");
cfg.put("length", "12");
But I'd have to say if("fieldName".equals("accountNumber")) then assign accountNumber; is there a way to implement this in such a way that I could avoid implementing all this decisions? right now with my solution I don't have to use ifs, I only say accountNumber = array[0]; and that's it, but I don't think that's a good solution and I think that using Property would be more elegant or efficient
EDIT:
This probably needs some more clarification, this data I'm showing is part of a parsing program that I'm currently doing for a client; the data holds information for many many of their customers and I have to parse a huge mess of data that I receive from them, into something more readable in order to convert it to a PDF file, so far the program is under production but I'm trying to refactor it a little bit. All the customer's information is saved into different Registry classes, each class having it's own set of fields with unique information, lets say that this is what RegistryYY would look like:
class RegistryYY extends Registry{
String name;
String lastName;
PhysicalAddress address;
public RegistryYY(String dataFromFile) {
}
}
I want to implement the Property solution, because in that way, I could make the Property for parsing the file, or interpreting the data correctly to be owned by each Registry class, I mean, a Registry should know what data it needs from the data received from the file right?, I think that if I do it that way, I could make each Registry an Observer and they would decide if the current line read from the file belongs to them by checking the registry name stored in the current line and then they'd return an initialized Registry to the calling object which only cares about receiving and storing a Registry class.
EDIT 2:
I created this function to return the value stored in each line's position:
public static String getField(String fieldParams, String rawData){
// splits the field
String[] fields = fieldParams.split("-");
int fieldStart = Integer.parseInt(fields[0]); // get initial position of the field
int fieldLen = Integer.parseInt(fields[1]); // get length of field
// gets field value
String fieldValue = FieldParser.getStringValue(rawData, fieldStart, fieldLen);
return fieldValue;
}
Which works with the CSV file, I'd like to change the implementation to work with the Property file instead.
Is there any reason why you need to have the record layout exposed to the outside world ? does it need to be configurable ?
I think your proposed approached of using the Property file is better than your current approach of using the CSV file since it is more descriptive and meaningful. I would just add a "type" attribute to your Property definition as well to enforce your conversion i.e. for Numeric/String/Date/Boolean.
I wouldnt use an "if" statement to process your property file. You can load all the properties into an Array at the beginning and then iterate around the array for each line of your data file and process that section accordingly something like pseudo code below,
for each loop of data-file{
SomeClass myClass = myClassBuilder(data-file-line)
}
myClassBuilder SomeClass (String data-file-line){
Map<column, value> result = new HashMap<>
for each attribute of property-file-list{
switch attribute_type {
Integer:
result.put(fieldname, makeInteger(data-file-line, property_attribute)
Date:
result.put(fieldname, makeDate(data-file-line, property_attribute)
Boolean :
result.put(fieldname, makeBoolean(data-file-line, property_attribute)
String :
result.put(fieldname, makeBoolean(data-file-line, property_attribute)
------- etc
}
}
return new SomeClass(result)
}
}
If your record layout doesnt need to be configurable then you could do all the conversion inside your Java application only and not even use a Property file.
If you could get your data in XML format then you could use the JAXB framework and simply have your data definition in an XML file.
First of all, thanks to the guys who helped me, #robbie70, #RC. and #VinceEmigh.
I used YAML to parse a file called "test.yml" with the following information in it:
statement:
- fieldName: accountNumber
startPosition: 128
length: 12
- fieldName: cardNumber
startPosition: 140
length: 22
- fieldName: registryName
startPosition: 162
length: 2
This is what I made:
// Start of main
String fileValue = "0222000000002222F 00000000000111110001000000099999444444******4444 YY";
YamlReader reader = new YamlReader(new FileReader("test.yml"));
Object object = reader.read();
System.out.println(object);
Map map = (Map) object;
List list = (List) map.get("statement");
for(int i = 0; i < list.size(); i++) {
Map map2 = (Map) list.get(i);
System.out.println("Value: " + foo(map2, fileValue));
}
}
// End of main
public static String foo(Map map, String source) {
int startPos = Integer.parseInt((String) map.get("startPosition"));
int length = Integer.parseInt((String) map.get("length"));
return getField(startPos, length, source);
}
public static String getField(int start, int length, String source) {
return source.substring(start, start+length);
}
It correctly displays the output:
Value: 000000099999
Value: 444444******4444
Value: YY
I know that maybe the config file has some lists and other unnecessary values and what nots, and that maybe the program needs a little improvement, but I think that I can take it from here and implement what I had in mind.
EDIT:
I made this other one, using Apache Commons, this is what I have in the configuration property file:
#properties defining the statement file
#properties for account number
statement.accountNumber.startPosition = 128
statement.accountNumber.length = 12
statement.account.rules = ${statement.accountNumber.startPosition} ${statement.accountNumber.length}
#properties for card number
statement.cardNumber.startPosition = 140
statement.cardNumber.length = 22
statement.card.rules = ${statement.cardNumber.startPosition} ${statement.cardNumber.length}
#properties for registry name
statement.registryName.startPosition = 162
statement.registryName.length = 2
statement.registry.rules = ${statement.registryName.startPosition} ${statement.registryName.length}
And this is how I read it:
// Inside Main
String valorLeido = "0713000000007451D 00000000000111110001000000099999444444******4444 YY";
Parameters params = new Parameters();
FileBasedConfigurationBuilder<FileBasedConfiguration> builder =
new FileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class)
.configure(params.properties()
.setFileName("config.properties"));
try {
Configuration config = builder.getConfiguration();
Iterator<String> keys = config.getKeys();
String account = getValue(getRules(config, "statement.account.rules"), valorLeido);
String cardNumber = getValue(getRules(config, "statement.card.rules"), valorLeido);
String registryName = getValue(getRules(config, "statement.registry.rules"), valorLeido);
} catch (org.apache.commons.configuration2.ex.ConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// End of Main
public static String getRules(Configuration config, String rules) {
return config.getString(rules);
}
public static String getValue(String rules, String source) {
String[] tokens = rules.split(" ");
int startPos = Integer.parseInt(tokens[0]);
int length = Integer.parseInt(tokens[1]);
return getField(startPos, length, source);
}
I'm not entirely sure, I think that with the YAML file it looks simpler, but I really like the control I get with the Apache Commons Config, since I can pass around the Configuration object to each registry, and the registry knows what "rules" it wants to get, let's say that the Registry class only cares about "statement.registry.rules" and that's it, with the YAML option I'm not entirely sure of how to do that yet, maybe I'll need to experiment with both options a little bit more, but I like where this is going.
PS:
That weird value I used in fileValue is what I'm dealing with, now add nearly 1,000 characters to the length of the line and you'll understand why I want to have a config file for parsing it (don't ask why....clients be crazy)
I was confused with the arguments of the lines "Instances originalTrain=" can anyone please help me to correct this error since I was new to this weka. We are creating a disease prediction system using weka in java.
import weka.classifiers.Classifier;
import weka.core.Instances;
public class Main {
public static void main(String[] args) throws Exception
{
String rootPath="/some/where/";
Instances originalTrain= //instances here (don't know to complete this statement)
//load model
Classifier cls = (Classifier) weka.core.SerializationHelper.read(rootPath+"tree.model");
//predict instance class values
Instances originalTrain= //load or create Instances to predict (This statement too)
//which instance to predict class value
int s1=0;
//perform your prediction
double value=cls.classifyInstance(originalTrain.instance(s1));
//get the prediction percentage or distribution
double[] percentage=cls.distributionForInstance(originalTrain.instance(s1));
//get the name of the class value
String prediction=originalTrain.classAttribute().value((int)value);
System.out.println("The predicted value of instance "+
Integer.toString(s1)+
": "+prediction);
//Format the distribution
String distribution="";
for(int i=0; i <percentage.length; i=i+1)
{
if(i==value)
{
distribution=distribution+"*"+Double.toString(percentage[i])+",";
}
else
{
distribution=distribution+Double.toString(percentage[i])+",";
}
}
distribution=distribution.substring(0, distribution.length()-1);
System.out.println("Distribution:"+ distribution);
}
}
For completeness, the code snippet in the question originates from Get prediction percentage in WEKA using own Java code and a model.
originalTrain should be your training instances. There are two ways that I know to add instances to originalTrain.
This method loads data from an .arff file and is based on instructions found here.
// rootPath should be where the .arff file is held
// filename should hold the complete name of the .arff file
public static Instances instanceData(String rootPath, String filename) throws Exception
{
// initialize source
DataSource source = null;
Instances data = null;
source = new DataSource(rootPath + filename);
data = source.getDataSet();
// set the class to the last attribute of the data (may need to tweak)
if (data.classIndex() == -1)
data.setClassIndex(data.numAttributes() -1 );
return data;
}
You can create and add instance manually as described in this answer Define input data for clustering using WEKA API .
this is my class of table that includes Column that has Column name its data type and bool if its a primary key or not; and this list of columns combine to form one table.
I want to write this by calling a func public void SaveToFile(){} i have tried something as well but im confused how to write it by not deleting or changing the previous record(no Over writing); as i want a file of Database having each table object and its columns saperately by a line space.
you may take help from viewColumn(); func works correctly.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class Table
{
private ArrayList<Column> columns;
private String NAME;
private static int count=0;
public Table()
{
columns = new ArrayList<Column>();
NAME=new String();
this.NAME="Table"+count;
count++;
}
public void AddColumn(Column column)
{
columns.add(column);
}
public void SaveToFile() throws IOException
{
File f=new File("Database.txt");
f.createNewFile();
BufferedReader b =new BufferedReader(new FileReader(f));
ArrayList<Column> col =new ArrayList<Column>();
String S =b.readLine();
// *********************
//*********************
}
public boolean DeleteColumn(String name)
{
for (Column c : columns)
{
if (c.getname().equals(name)) {return columns.remove(c);}
}
return false;
}
public void viewColumns()
{
System.out.append(NAME+" ");
for(Column c: columns)
{
System.out.append("\n");
System.out.append(c.getname()+" ");
System.out.append((CharSequence) c.getdatatype()+" ");
if(c.getPK()==true)
{
System.out.print(true);
}
}
}
public String getNAME() {
return NAME;
}
}
It looks to me like you are trying to implement a "database" using a flat file. This is not a good idea. And one of the reasons that it is not a good idea is that it is difficult to update and delete records ... without rewriting the entire file.
I suggest that you use a real database (or SQLite) rather than trying to reinvent the wheel.
no i just want to create a file of a database... its a small project. i just want to keep record of how many tables are there in the Database and columns of each tables.
What you are implementing is a mini database that describes the Database. But there are better ways to do this.
Store the information in a new table in the real database.
The information you are trying to store is already present in the real database and available via the JDBC metadata API. Use that instead of replicating the metadata.
In addition to the problem of "reinventing the wheel" in your mini-database implementation, your current approach is creating a (redundant) 2nd description of the actual Database that has to (somehow) be kept in step with the real database's table structure metadata.
I used the following coding to display user accounts in my domain.But in that coding it display only first 100 records.But in my domain nearly 500 users account.I don't know what problem in this coding
import java.net.URL;
import java.util.List;
import com.google.gdata.client.appsforyourdomain.UserService;
import com.google.gdata.data.appsforyourdomain.provisioning.UserEntry;
import com.google.gdata.data.appsforyourdomain.provisioning.UserFeed;
public class Readuser {
public int i3;
public String rn[]=new String[100];
public void read(){
try
{
// Create a new Apps Provisioning service
UserService myService = new UserService("My Application");
myService.setUserCredentials(admin,password);
// Get a list of all entries
URL metafeedUrl = new URL("https://www.google.com/a/feeds/"+domain+"/user/2.0/");
System.out.println("Getting user entries...\n");
UserFeed resultFeed = myService.getFeed(metafeedUrl, UserFeed.class);
List<UserEntry> entries = resultFeed.getEntries();
for(i3=0; i3<entries.size(); i3++) {
UserEntry entry = entries.get(i3);
rn[i3]= entry.getTitle().getPlainText();
System.out.println(rn[i3]);
}
System.out.println("\nTotal Entries: "+entries.size());
}
catch(Exception e) { System.out.print(e);}
}
public static void main(String args[])
{
Readuser ru=new Readuser();
ru.read();
}
}
You only allocate 100 entries.
public String rn[]=new String[100];
Hint from your code : public String rn[]=new String[100];
Do you really need to have i3 and rn as class members ? Do you really need rn ? A List seems more comfortable as an Object than a String[].
There is no need for the string array (String[]).
Arrays are fixed size; and in this case you have allocated 100 "slots" for Strings, and when You try to assign a string to position 100 ( you know, the 101:th string) it fails.
You catch an exception in the end. Print the stack trace to find out whats going on
catch(Exception e) {
e.printStackTrace();
}
Learn to read it an find out what is says... However you should not catch the exception in this method. It is better to abort whatever the program was doing. Catch it in your main method - just printing or logging it is fine, so that you can correct the programming error.
Anyway; The result you get is a List of user entries. Lists are part of the (java.util)collections framework. Collections have a lot of features; in this case you want to iterate over all entries in the list. You can do this by using the iterator() method -read the javadoc...OR you can use for-loop syntactic sugar for doing this:
for( UserEntry user : entries ) {
// user is the current UserEntry
System.out.println(user.getTitle().getPlainText());
}
The variables i3 and rn are no good... They shouldn't be class variables, and if you need "temporary" variables, define them close to where you are going to use them.
As for naming of variables, a name like "entry" is less useful than "user". Actually a class called UserEntry should probably be called just User, but I don't know about this API, so...