i want to count the total numer of variables from text file in java for this purpose we use this code
try {
BufferedReader reader = new BufferedReader(new FileReader(fn));
String line = reader.readLine();
while(line !=null)
{
Scanner fs = new Scanner(reader);
while(fs.hasNext())
{
String s = fs.next();
if( s.startsWith("int")) {
s1 = ";" ;
while(!(s1.equals(s2))){
Scanner fd = new Scanner(reader);
while(fd.hasNext()){
c = fd.next();
if(c.contains(","))
cint++;
else
cint++;
if(c.startsWith(";"))
break;
}
s2 = c ;
}
}
if(s.startsWith("short")) {
cshort++;
}
if(s.startsWith("byte")) {
cbyte++;
}
if(s.startsWith("long")) {
clong++;
}
if(s.startsWith("float")) {
cfloat++;
}
if(s.startsWith("boolean")) {
cboolean++;
}
if(s.startsWith("double")) {
cdouble++;
}
if(s.startsWith("char")) {
cchar++;
}
if(s.startsWith("abstract")) {
cabstract++;
}
if(s.startsWith("continue")) {
ccontinue++;
}
if(s.startsWith("switch")) {
cswitch++;
}
if(s.startsWith("assert")) {
cassert++;
}
if(s.startsWith("default")) {
cdefault++;
}
if(s.startsWith("goto")) {
cgoto++;
}
if(s.startsWith("package")) {
cpackage++;
}
if(s.startsWith("synchronized")) {
csync++;
}
if(s.startsWith("do")) {
cdo++;
}
if(s.startsWith("if")) {
cif++;
}
if(s.startsWith("private")) {
cprivate++;
}
if(s.startsWith("this")) {
cthis++;
}
if(s.startsWith("break")) {
cbreak++;
}
if(s.startsWith("implements")) {
cimplements++;
}
if(s.startsWith("protected")) {
cprotected++;
}
if(s.startsWith("catch")) {
ccatch++;
}
if(s.startsWith("extends")) {
cextends++;
}
if(s.startsWith("try")) {
ctry++;
}
if(s.startsWith("final")) {
cfinal++;
}
if(s.startsWith("interface")) {
cinterface++;
}
if(s.startsWith("static")) {
cstatic++;
}
if(s.startsWith("void")) {
cvoid++;
}
if(s.startsWith("instanceof")) {
cinstanceof++;
}
if(s.startsWith("class")) {
cclass++;
}
if(s.startsWith("finally")) {
cfinally++;
}
if(s.startsWith("strictfp")) {
cstrictfp++;
}
if(s.startsWith("volatile")) {
cvolatile++;
}
if(s.startsWith("const")) {
cconst++;
}
if(s.startsWith("native")) {
cnative++;
}
if(s.startsWith("super")) {
csuper++;
}
if(s.startsWith("while")) {
cwhile++;
}
if(s.startsWith("for")) {
cfor++;
}
}
line = reader.readLine();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
insert();
The problem is this it gives wrong number of integer variable
please can help me any on for this
Try adding some else if's instead of a million ifs. If a variable starts with one thing its not going to start with another. For example:
if(s.startsWith("short")) {
cshort++;
}
else if(s.startsWith("byte")) {
cbyte++;
}
That will also cut down on the compile time for your program. If you have access to the file you could make each variable on a separate line to make it easier to debug and read in.
Lets just look at the code that attempts to count int variables:
if( s.startsWith("int")) {
s1 = ";" ;
while(!(s1.equals(s2))){
Scanner fd = new Scanner(reader);
while(fd.hasNext()){
c = fd.next();
if(c.contains(","))
cint++;
else
cint++;
if(c.startsWith(";"))
break;
}
s2 = c ;
}
}
Why is that going to give incorrect counts?
You are treating every word that starts with "int" as an int keyword. But it isn't. What about internal or international ...
What about int in comments? Comments should be ignored.
What about int[] myarray;? That's not int variable. It is a int[] variable.
What about return (int) someVariable; ? That is a typecast, not a declaration.
What about public int someMethod() { ... } ? The return type is not a variable.
What about public void method(int a, char b) { ... } ? That's declaring an int variable ... but your code will (I think) incorrectly count it as two int variables.
And so on.
Your approach would be best described as crude one-pass pattern matching, implemented directly as code. Basically, this approach to "analysing" source code is doomed to fail.
What you really need to do is to parse the Java source code properly using a parser that recognizes the Java grammar. You could:
write your own Java parser, or
make use of an existing Java parser, or
look for an existing Java grammar that is suitable for input to ANTLR or JavaCC or some other Java parser generator system (PGS).
Once you've done that, you could either walk an AST data structure emitted by the parser, or embed your "variable counting" code into the grammar in the PGS input file.
There is another approach (from the linked Q&A). Compile the source file, use Class.forName() to load it, and then use reflection to find Field objects for the static and instance variables. At a pinch, you could even count the parameters in the method signatures via the Method objects. But local variables are not exposed by reflection ...
Related
I am a beginner programmer so please excuse any technically incorrect statements/incorrect use of terminology.
I am trying to make a program that reduces CNF SAT in DIMACS format to 3SAT, and then from 3SAT to 3Graph Coloring, and then 3Graph coloring to SAT again. The idea is to make it circular so that the output from one reduction can be piped straight into the input of another, AKA if you reduce a CNF to 3SAT, the program should automatically reduce the 3SAT to Graph coloring after if the use specifies it to.
I have chosen to represent CNFs in a LinkedHashMap in a class called CNFHandler. The LinkedHashMap is where File = the DIMACS cnf formatted file and the CNF object is the CNF (which contains an ArrayList of Clause objects) that corresponds to the CNF.
In my CNFHandler class, I have a reduce object, and it's in this object that I am trying to initiate my piping functionality:
package CNFHandler;
import SAT_to_3SAT_Reducer.Reducer;
import java.io.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
public class CNFHandler {
private Map<File, CNF> allCNFs = new LinkedHashMap<>();
private CNFReader reader;
private Reducer reducer = new Reducer();
// PIPES
private Optional<ObjectInputStream> inputPipe;
private Optional<ObjectOutputStream> outputPipe;
// Instantiate Pipes
public void setInputPipe(ObjectInputStream inputStream) {
this.inputPipe = Optional.of(inputStream);
}
public void setOutputPipe(ObjectOutputStream outputStream) {
this.outputPipe = Optional.of(outputStream);
}
//...
// Skipping lines for brevity
//...
public void reduce(String filePath) {
File path = new File(filePath);
addCNF(filePath);
CNF result = reducer.reduce(allCNFs.get(path));
if (!outputPipe.isPresent()) {
System.out.println(result.toDIMACS());
} else {
try {
outputPipe.get().writeObject(result);
outputPipe.get().close();
} catch (Exception e){
e.printStackTrace();
}
}
}
}
When I try to run "writeObject" (within the try block in the reduce() method) the program doesn't seem to go past that point. I've tried using breakpoints in IntelliJ to see what's going on, but the best I could figure out was as follows:
A Native method called waitForReferencePendingList() seems to be stuck waiting for something, and that's why it won't go past the writeObject method
IntelliJ tells me "Connected to the target VM, address: '127.0.0.1:51236', transport: 'socket'" but I'm not sure why because I'm not using Sockets anywhere in my program
Here is the code for my Main method where I instantiate the ObjectOutputStreams :
import CNFHandler.CNFHandler;
import GraphHandler.GraphHandler;
import java.io.*;
public class Main {
public static void main(String[] args) {
try {
String inFile = "short_cnf.cnf";
PipedOutputStream _S_3S_OUT_PIPE_STREAM = new PipedOutputStream();
PipedInputStream _S_3S_IN_PIPE_STREAM = new PipedInputStream();
_S_3S_IN_PIPE_STREAM.connect(_S_3S_OUT_PIPE_STREAM);
ObjectOutputStream _S_3S_OUT_OBJECT_STREAM = new ObjectOutputStream(_S_3S_OUT_PIPE_STREAM);
ObjectInputStream _S_3S_IN_OBJEECT_STREAM = new ObjectInputStream(_S_3S_IN_PIPE_STREAM);
CNFHandler handler = new CNFHandler();
handler.setOutputPipe(_S_3S_OUT_OBJECT_STREAM);
handler.reduce(inFile);
PipedOutputStream _3S_G_OUT = new PipedOutputStream();
PipedInputStream _3S_G_IN = new PipedInputStream();
_3S_G_IN.connect(_3S_G_OUT);
ObjectOutputStream _3S_G_OUT_STREAM = new ObjectOutputStream(_3S_G_OUT);
ObjectInputStream _3S_G_IN_STREAM = new ObjectInputStream(_3S_G_IN);
GraphHandler graphHandler = new GraphHandler();
graphHandler.setInputPipe(_S_3S_IN_OBJEECT_STREAM);
graphHandler.setOutputPipe(_3S_G_OUT_STREAM);
graphHandler.reduce();
} catch (IOException e) {
e.printStackTrace();
}
}
}
The other weird thing is that the writeObject() method seems to work if I use a different kind of object, for example, if I instantiate a String within the writeObject() method in the same place it's being called in reduce(), or if I instantiate a new CNF object in the same place, it WILL write the object. But I can't do it this way because I have to pass along the values of the object as well (the clauses, etc.) so I don't know what to do.
This is my CNF class, in brief:
package CNFHandler;
import java.io.Serializable;
import java.util.*;
public class CNF implements Serializable {
protected int numVars;
protected int numClauses;
protected String fileName;
// store all variables with no duplicates
protected Set<String> allLiterals = new HashSet<>();
protected ArrayList<Clause> clauses = new ArrayList<>();
/*
for printing to DIMACS: keep track of the max # of
literals that are needed to print a clause
for example if all clauses in the CNF file contain
2 literals, and only one contains 3 literals
then the literalsize will be 3 to ensure things
are printed with proper spacing
*/
protected int literalSize = -20;
/*
keep track of the label referring to the highest #ed literal
just in case they are not stored in order -- this way when we perform
reductions we can just add literals to the end and be sure we are not
duplicating any
*/
protected int highestLiteral = -10;
public CNF(String fileName) {
this.fileName = fileName;
}
protected void addClause(String[] inputs) {
try {
Clause clauseToAdd = new Clause();
// add literals to the hashset, excluding dashes that indicate negative literals
for (int i = 0; i < inputs.length - 1; i++) {
// removing whitespace from the input
String toAdd = inputs[i].replaceAll("\\s+", "");;
// in case the variable is false (has a dash before the int), remove the dash to standardize storage
String moddedToAdd = inputs[i].replaceAll("[-]*", "");
/*
if an unknown variable is in the stream, reject it.
(we're basically checking here if the variable set is full,
and if it is and the variable we're trying to add is new,
then it can't be added)
*/
if ((!allLiterals.contains(moddedToAdd)) && (allLiterals.size() == numVars) && (moddedToAdd.trim().length() > 0)) {
throw new FailedCNFException();
}
// add the original input (so not the regex'd one but the one that would be false if it had been input as false
clauseToAdd.addLiteral(toAdd);
if (!allLiterals.contains(moddedToAdd) && !moddedToAdd.equalsIgnoreCase("")) {
allLiterals.add(moddedToAdd);
/*
change the highestLiteral value if the literal being added is "bigger" than the others that have been seen
*/
if(highestLiteral < Integer.parseInt(moddedToAdd)) {
highestLiteral = Integer.parseInt(moddedToAdd);
}
}
}
if (clauseToAdd.getNumberOfLiterals() > literalSize) {
literalSize = clauseToAdd.getNumberOfLiterals();
}
clauses.add(clauseToAdd);
} catch (FailedCNFException e) {
System.out.println("The number of variables that have been introduced is too many!");
}
}
public void makeClause(String[] inputs) {
try {
if (inputs[inputs.length - 1].equals("0")) {
addClause(inputs);
} else throw new FailedCNFException();
} catch (FailedCNFException f) {
System.out.println("There is no 0 at the end of this line: ");
for (String s : inputs ) {
System.out.print(s + " ");
}
System.out.println();
}
}
public void initializeClauses (String[] inputs) {
setNumVars(inputs[2]);
setNumClauses(inputs[3]);
}
public String toDIMACS () {
String toReturn = "p cnf " + getNumVars() + " " + getNumClauses() + "\n";
for(int i = 0; i < clauses.size()-1; i++){
Clause c = clauses.get(i);
toReturn += c.toDIMACS(literalSize) + "\n";
}
toReturn += clauses.get(clauses.size()-1).toDIMACS(literalSize);
return toReturn;
}
/*
Override tostring method to print clauses in human-readable format
*/
#Override
public String toString () {
if(highestLiteral != -10) {
String toReturn = "(";
for (int i = 0; i < clauses.size() - 1; i++) {
Clause c = clauses.get(i);
toReturn += c + "&&";
}
toReturn += clauses.get(clauses.size() - 1).toString() + ")";
return toReturn;
} else {
return "Add some clauses!";
}
}
public String toString (boolean addFile) {
String toReturn = "";
if (addFile) {
toReturn += "src/test/ExampleCNFs/" + fileName + ".cnf: \n";
}
toReturn += "(";
for(int i = 0; i < clauses.size()-1; i++){
Clause c = clauses.get(i);
toReturn += c + "&&";
}
toReturn += clauses.get(clauses.size()-1).toString() + ")";
return toReturn;
}
//=============================================================================
// HELPER FUNCTIONS
//=============================================================================
public void setNumVars(String vars) {
numVars = Integer.parseInt(vars);
}
public void setNumClauses(String clauses) {
numClauses = Integer.parseInt(clauses);
}
public Clause getClause(int index) {
return clauses.get(index);
}
public void addLiteral(int newLiteral) {
allLiterals.add(String.valueOf(newLiteral));
}
public void addLiterals(Set<String> newLiterals) {
allLiterals.addAll(newLiterals);
}
public void addClauses(ArrayList<Clause> toAdd, int maxLiterals) {
clauses.addAll(toAdd);
numClauses += toAdd.size();
// update literalsize if need be
if (maxLiterals > literalSize) {
literalSize = maxLiterals;
}
}
//=============================================================================
// GETTERS AND SETTERS
//=============================================================================
public void setNumVars(int numVars) {
this.numVars = numVars;
}
public void setNumClauses(int numClauses) {
this.numClauses = numClauses;
}
public int getNumVars() {
return numVars;
}
public int getNumClauses() {
return numClauses;
}
public ArrayList<Clause> getClauses() {
return clauses;
}
public Set<String> getAllLiterals() {
return allLiterals;
}
//
// LITERAL SIZE REPRESENTS THE MAXIMUM NUMBER OF LITERALS A CLAUSE CAN CONTAIN
//
public int getLiteralSize() {
return literalSize;
}
public void setLiteralSize(int literalSize) {
this.literalSize = literalSize;
}
public String getFilePath() {
return "src/test/ExampleCNFs/" + fileName + ".cnf";
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
//
// HIGHEST LITERAL REPRESENTS THE HIGHEST NUMBER USED TO REPRESENT A LITERAL
// IN THE DIMACS CNF FORMAT
//
public int getHighestLiteral() {
return highestLiteral;
}
public void setHighestLiteral(int highestLiteral) {
this.highestLiteral = highestLiteral;
}
public void setHighestLiteral(String highestLiteral) {
this.highestLiteral = Integer.parseInt(highestLiteral);
}
}
Can someone give me some insight as to what's going on here, please? Thank you very much.
First of all, neither of the symptoms are actually relevant to your question:
A Native method called waitForReferencePendingList() seems to be stuck waiting for something.
You appear to have found an internal thread that is dealing with the processing of Reference objects following a garbage collection. It is normal for it to be waiting there.
IntelliJ tells me "Connected to the target VM, address: '127.0.0.1:51236', transport: 'socket'"
That is Intellij saying that it has connected to the debug agent in the JVM that is running your application. Again, this is normal.
If you are trying to find the cause of a problem via a debugger, you need to find the application thread that is stuck. Then drill down to the point where it is actually stuck and look at the corresponding source code to figure out what it is doing. In this case, you need to look at the standard Java SE library source code for your platform. Randomly looking for clues rarely works ...
Now to your actual problem.
Without a stacktrace or a minimal reproducible example, it is not possible to say with certainty what is happening.
However, I suspect that writeObject is simply stuck waiting for something to read from the "other end" of the pipeline. It looks like you have set up a PipedInputStream / PipedOutputStream pair. This has only a limited amount of buffering. If the "writer" writes too much to the output stream, it will block until the "reader" has read some data from the input stream.
The other weird thing is that the writeObject() method seems to work if I use a different kind of object ...
The other kind of object probably has a smaller serialization which fits into the available buffer space.
So obviously I'm really new to Java and I'm trying to read a text file and put in a loop. Each iteration of the loop will read one line and assign it to a variable. I have a few methods inside my class that will help with this. However, when I assign the variables through the loop, and print them out, it prints out nothing. I've tried many different things and spent hours trying to get this to work but to no avail.
Here is my code:
public void readFile(File value) {
try {
Scanner inputFile = new Scanner(value);
for (int i = 0; i == 4; i++) {
switch(i) {
case 0:
setId(inputFile.nextLine());
case 1:
setDescription(inputFile.nextLine());
case 2:
setDepartment(inputFile.nextLine());
case 3:
setPrice(inputFile.nextLine());
case 4:
setLocation(inputFile.nextLine());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
//toString
public String toString() {
return id + description + department + price + location;
}
}
The setId, setDesc...etc are my methods inside my class. I have a main program that calls upon these methods:
stringClass stringTest = new stringClass();
File myFile = new File("readFromFile.txt");
try {
stringTest.readFile(myFile);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(stringTest);
However, when it prints, it only prints out null(which is the default value I gave to the id/description/etc variables within my default constructor. Any help would be greatly appreciated thanks!
I'm building a small application in Java, small game mechanics but nothing serious. I have a class which purpose is to fetch data from a file. But when I declare the two classes to read from it the program justs ignore everything and continues. As a result, when I try to access the respective lists it gives me null pointer exception. Code of the method that fetches data below:
public void getData(int l, player tmp, level le) {
String[] dataPlayer;
String[] dataLevel;
try {
//FileReader f = new FileReader(this.levelPath.concat(Integer.toString(l)));
File f = new File(this.levelPath.concat(Integer.toString(l)));
BufferedReader buff = new BufferedReader(new FileReader(f));
System.out.println("Reached");
boolean eof = false;
while (!eof) {
String b = buff.readLine();
if (b == null)
eof = true;
else {
if (b.contains("player")) {
dataPlayer = b.split("-");
for (int i = 0; i < dataPlayer.length; i++) {
if (i == 0)
continue;
items it = new items(dataPlayer[i]);
tmp.setInventory1(it);
}
}else if (b.contains("level")) {
dataLevel = b.split("-");
for (int i = 0; i < dataLevel.length; i++) {
if (i == 0)
continue;
items it = new items(dataLevel[i]);
le.setSpecific(it);
}
}
}
}
}catch (IOException i) {
i.getMessage();
}
}
File contents of the file "levelData1":
player-hat
player-flashlight
level-flower
level-rock
player-adz
The problem with this particular problem was the path, it needed the absolute like that /home/toomlg4u/IdeaProjects/javaProject/src/Data/levelData.
You're doing a lot of things inside that try/catch that may not throw an IOException. If you get any other exception, it's not going to be caught. Depending on what other exception handling you have in place, that may cause weird behavior. For debugging, you could catch all exceptions, and see if you're getting something else.
If you want to remain to your loop code then you can refactor your code to look like this one:
public void getData(int l, player tmp, level le) {
try (BufferedReader buff = new BufferedReader(new FileReader(new File(this.levelPath + l)))) {
String b;
while ((b = buff.readLine()) != null) {
if (b.contains("player")) {
String[] dataPlayer = b.split("-");
items it = new items(dataPlayer[1]); //because you know that you will have an array with only 2 elements
tmp.setInventory1(it);
}else if (b.contains("level")) {
String[] dataLevel = b.split("-");
items it = new items(dataLevel[1]); //because you know that you will have an array with only 2 elements
le.setSpecific(it);
}
}
}catch (IOException e) {
e.printStackTrace();
}
}
It is a little bit better than that you have, easier to debug and to read. I advice you to read about try with resources.
As a rule of thumb, each time when you open a stream you have to close it. When you don't open it yourself then don't close it.
This is how it should look like a decent program in Java:
private Stream<Items> asStreamOfItems(String line){
return Stream.of(line.split("-")).skip(1).map(Items::new);
}
public void parseFile(String pathToTheFile) throws IOException {
List<String> lines = Files.readAllLines(Paths.get(pathToTheFile));
List<Items> players = lines.stream().filter(line -> line.contains("player")).flatMap(this::asStreamOfItems).collect(Collectors.toList());
List<Items> levels = lines.stream().filter(line -> line.contains("level")).flatMap(this::asStreamOfItems).collect(Collectors.toList());
........
}
In this case all your weird errors will vanish.
After you edited the post I saw your file content. In this case the code should look like this one:
class Items {
private final String name;
public Items(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static Items parse(String line) {
return new Items(line.split("-")[1]);
}
}
public void parseFile(String pathToTheFile) throws IOException {
List<String> lines = Files.readAllLines(Paths.get(pathToTheFile));
List<Items> players = lines.stream().filter(line -> line.contains("player")).map(Items::parse).collect(Collectors.toList());
List<Items> levels = lines.stream().filter(line -> line.contains("level")).map(Items::parse).collect(Collectors.toList());
..............
}
Btw, you broke a lot of Java and general programming rules like:
using continue is a bad practice. It should be used only in extreme cases because it makes the code difficult to read.
the class name in Java should be in the CamelCase notation
one method should have only one responsibility
DON'T mutate the object inside of a method (example: tmp.setInventory1(it);) very very very bad practice
when you work with streams use try with resource or try/catch/finally to close your stream after you finish the reading.
Before jumping to write code explore the JAVA IO SDK to look for better methods to read from files
I am working in a desktop application for windows using Java. In my application, there is a requirement to search all .php. To do this, I use recursive methods.
import java.io.File;
public class Copier {
public static void find(String source,String rep) {
File src = new File(rep);
if (src!= null && src.exists() && src.isDirectory()) {
String[] tab = src.list();
if (tab != null) {
for(String s : tab) {
File srcc = new File(rep+"\\"+s);
if (srcc.isFile()) {
if (srcc.getName().matches(".*"+source+"$")) {
System.out.println(s);
}
} else {
find(source,srcc.getAbsolutePath());
}
}
} else {
//System.out.println(" list is null");
}
}
}
public static void main(String[] args) {
try {
find(".java", "C:\\");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Is it possible to do this with an iterative algorithm?
Of course. Use breadth-first-search with queue. You start from C:\ and at every step you pop the top folder from the queue and push all subfolders to the end of the queue.
Pseudocode follows:
queue.push("C:\");
while (!queue.empty()) {
String topFolder = queue.pop();
foreach (subFolder of topFolder) {
queue.push(subFolder);
}
}
I can't see why you want to get rid of recursion although theoretically what you are looking for is possible.
But a good way to get a faster program could be to use a filefilter when you list the children of a directory. One for directories and one for matching files (this one should use a java.util.regexp.Pattern).
-updated
You can find the doc for the overload of File.list to use here. And for the pattern, you could something like a local variable (outside your loop or a data member if you use recursion).
Pattern p = Pattern.compile( ".*"+source+".*" );
boolean found = p.matcher( p.matcher( srcc.getName() ).matches() );
Oh, and by the way, don't convert srcc into a file ! Work with strings and build as few objects as you can.
You can always use a queue in place of recursion. In this case, I think it makes the code look a little bit easier to read. Often you'll get better performance from an iterative implementation than a recursive one though in this case, they both run at nearly the same speed (at least on my machine).
public static List<String> find(final String source, final String directory)
{
List<String> results = new LinkedList<String>();
Stack<String> stack = new Stack<String>();
stack.add(directory);
String rep;
while (!stack.isEmpty()) {
rep = stack.pop();
File src = new File(rep);
if (src != null && src.exists() && src.isDirectory()) {
String[] tab = src.list();
if (tab != null) {
for (String s : tab) {
File srcc = new File(rep + File.separatorChar + s);
if (srcc.isFile()) {
if (srcc.getName().matches(".*" + source + "$")) {
// System.out.println(s);
results.add(s);
}
} else {
stack.add(srcc.getAbsolutePath());
}
}
} else {
// System.out.println(" list is null");
}
}
}
return results;
}
I am trying to write a Java program that reads an input file consisting of URLs, extracts tokens from these, and keeps track of how many times each token appears in the file. I've written the following code:
import java.io.*;
import java.net.*;
public class Main {
static class Tokens
{
String name;
int count;
}
public static void main(String[] args) {
String url_str,host;
String htokens[];
URL url;
boolean found=false;
Tokens t[];
int i,j,k;
try
{
File f=new File("urlfile.txt");
FileReader fr=new FileReader(f);
BufferedReader br=new BufferedReader(fr);
while((url_str=br.readLine())!=null)
{
url=new URL(url_str);
host=url.getHost();
htokens=host.split("\\.|\\-|\\_|\\~|[0-9]");
for(i=0;i<htokens.length;i++)
{
if(!htokens[i].isEmpty())
{
for(j=0;j<t.length;j++)
{
if(htokens[i].equals(t[j].name))
{ t[j].count++; found=true; }
}
if(!found)
{
k=t.length;
t[k].name=htokens[i];
t[k].count=1;
}
}
}
System.out.println(t.length + "class tokens :");
for(i=0;i<t.length;i++)
{
System.out.println(
"name :"+t[i].name+" frequency :"+t[i].count);
}
}
br.close();
fr.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
But when I run it, it says: variable t not initialized.. What should I do to set it right?
Arrays in Java are fixed length, so I think what you really want to do is use a List<Tokens>
e.g.
List<Tokens> t = new ArrayList<Tokens>();
and
t.add(new Tokens(...))
unless you know in advance the number of items you'll have.
Initialize it:
// Declaration:
Tokens[] t;
// Initialization:
t = new Tokens[10]; // (Or whatever your desired length is)
You can combine declaration and initialization, and many do. I'm not a fan of doing so, but:
Tokens[] t = new Tokens[10];
You'll have the same issue with htokens.
You may want to look at the List interface (and its various implementations) instead of using an array.
Your code declares that t will represent an array of Tokens.
However, it does not define that array.
Per the Java Documentation, you need a line like:
t = new Tokens[10]; // Or however large the array should be
You are not initializing Tokens t[]; before using it.
EDIT : You need to it as below :
Tokens[] t = new Tokens[100]; // 100 is just an example
Or use List<Tokens>.
The modified code : < as per Brian Agnew's answer >
import java.io.*;
import java.net.*;
import java.util.*;
public class Main {
static class Tokens
{
String name;
int count;
Tokens(String str,int c)
{
name=str;
count=c;
}
}
public static void main(String[] args) {
String url_str,host;
String htokens[];
URL url;
boolean found=false;
List<Tokens> t = new ArrayList<Tokens>();
int i,j,k;
try
{
File f=new File("urlfile.txt");
FileReader fr=new FileReader(f);
BufferedReader br=new BufferedReader(fr);
while((url_str=br.readLine())!=null)
{
url=new URL(url_str);
host=url.getHost();
htokens=host.split("\\.|\\-|\\_|\\~|[0-9]");
for(i=0;i<htokens.length;i++)
{
if(!htokens[i].isEmpty())
{
found=false;
for(j=0;j<t.size();j++)
{
if(htokens[i].equals(t.get(j).name))
{
k=t.get(j).count+1;
t.set(j,new Tokens(htokens[i],k));
found=true;
break;
}
}
if(!found)
{
t.add(new Tokens(htokens[i],1));
}
}
}
}
System.out.println(t.size() + "class tokens :");
for(i=0;i<t.size();i++)
{
System.out.println("name :"+t.get(i).name+" freq :"+t.get(i).count);
}
br.close();
fr.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
Just to mention, you should not use C-like array syntax, i.e. use
String[] names = { "Walter", "Hans", "Bill" };
Instead of
String names[] = { "Walter", "Hans", "Bill" };