I have been trying and trying for a while with this and I just seem to cannot solve it.
I am supposed to extract classes from a Java-file and print in a shape UML-diagram, in the IDE or writing on a file
e.g the program
public class Complex {
private int re;
private int im;
public Complex(int re, int im) {
this.re = re;
this.im = im;
}
public Complex add(Complex h) {
return new Complex(this.re + h.re, this.im + h.im);
}
public Complex sub(Complex h) {
return new Complex(this.re - h.re, this.im - h.im);
}
public Complex mul(Complex h) {
int a = re;
int b = im;
int c = h.re;
int d = h.im;
return new Complex(a * c - b * d, b * c + a * d);
}
public Complex div(Complex h) {
int a = re;
int b = im;
int c = h.re;
int d = h.im;
return new Complex((a * c + b * d) / (c * c + d * d), (b * c - a * d)
/ (c * c + d * d));
}
public String toString() {
if (im >= 0) {
return re + " + " + im + "i";
} else
return re + " " + im + "i";
}
}
Should generate something like:
a Complex
b int re
b int re
a Complex(re:int, im:int)
a add():Complex
a sub():Complex
a mul():Complex
a div():Complex
a toString():String
a main()
I have started with stripping the first parenthesis from the file;
import java.io.*;
public class ClassExtract {
public static void main(String[] args) {
ClassExtract obj = new ClassExtract();
obj.removeBracket("Complexx.txt");
}
public void removeBracket(String filnamn) {
try {
File f = new File(filnamn);
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter("noparanthesis_" + filnamn);
BufferedWriter bw = new BufferedWriter(fw);
String rad = br.readLine();
while (rad != null) {
rad = rad.replaceAll("\\(", " ");
bw.write(rad);
bw.newLine();
rad = br.readLine();
}
bw.close();
br.close();
} catch (FileNotFoundException e) {
System.out.printf("The file " + filnamn + " was not found.");
} catch (IOException e) {
System.out.printf("Writing error.");
}
}
}
I have thought of different ways of approaching this problem. The way that I think would be easiest would be to strip everything after collected the head public class Complex, which would mean the rest of the file would look something like:
public Complex int re, int im
public Complex add Complex h
public Complex sub Complex h
etc and do the same and read the index of the lines.
I actually feel very lost and I have hard to tackle this problem, any help would really be appreciated.
As Qwe says in the comment, you would be much better off looking at the Java Reflection APIs.
These let you inspect a class and list its methods, superclasses, interfaces and so on.
By tackling this problem with regexes/text analysis, you are basically trying to write a partial Java parser, which is an entirely unnecessary amount of pain!
Related
I have a set of pdf files that I'm supposed to sort in reverse semantic order. The files are:
Release_Notes_CNV_22.3.pdf
Release_Notes_CNV_22.9.pdf
Release_Notes_CNV_22.12.pdf
Release_Notes_CNV_23.5.pdf
I have the following code to sort them. Unfortunately, the 22.3 file appears after 22.9. Can someone please tell me where I'm going wrong. A little help would be appreciated :D
The order I'm getting is:
Release_Notes_CNV_23.5.pdf
Release_Notes_CNV_22.12.pdf
Release_Notes_CNV_22.3.pdf // 22.3 appearing before 22.9
Release_Notes_CNV_22.9.pdf
The correct order should be:
Release_Notes_CNV_23.5.pdf
Release_Notes_CNV_22.12.pdf
Release_Notes_CNV_22.9.pdf
Release_Notes_CNV_22.3.pdf
My Code:
private String getReleaseNotesPdfFileAbsolutePath(long number) {
File folder = new File(String.format("%s%s%s", appHome, File.separator, releaseNotesFilesHomeFolderName));
File[] fileNames = folder.listFiles();
int i=1;
Arrays.sort(fileNames, new Comparator<File>() {
#Override
public int compare(File o1, File o2) {
float n1 = extractNumber(o1.getName());
float n2 = extractNumber(o2.getName());
int val = (int)n2 - (int)n1;
System.out.println(n2 + " " + (int)n2 + " : " + n1 + " " + (int)n1 + " : " + val);
return val;
}
private float extractNumber(String name) {
float i = 0;
try {
int s = name.lastIndexOf('_')+1;
int e = name.lastIndexOf('.');
String number = name.substring(s, e);
i = Float.parseFloat(number);
} catch(Exception e) {
i = 0; // if filename does not match the format
// then default to 0
}
return i;
}
});
for(File file : fileNames){
if( i == number ) {
return String.format("%s%s%s%s%s", appHome, File.separator, releaseNotesFilesHomeFolderName, File.separator, file.getName());
}
i = i+1;
}
return String.format("%s%s%s%s%s", appHome, File.separator, releaseNotesFilesHomeFolderName, File.separator, Constants.RELEASE_NOTES_PDF);
}
Tried the above code using comparator.
The problem comes from the fact that you compare decimal numbers. In the scope of decimals 0.12 < 0.3, because 0.3 = 0.30. But you want to compare decimal part as an integers, where 12 > 3. To achieve this you need to first compare integer parts, and then decimal parts.
You can represent this as custom class:
class MyDecimal {
private final int integerPart;
private final int decimalPart;
//constructor and getters
}
If you are using java 14 or above, record is even better.
Simplified example:
public class Test {
public static void main(String[] args) {
File[] fileNames = new File[]{new File("Release_Notes_CNV_23.5.pdf"),
new File("Release_Notes_CNV_22.12.pdf"),
new File("Release_Notes_CNV_22.3.pdf"),
new File("Release_Notes_CNV_22.9.pdf")};
Arrays.sort(fileNames, new Comparator<>() {
#Override
public int compare(File o1, File o2) {
MyDecimal n1 = extractNumber(o1.getName());
MyDecimal n2 = extractNumber(o2.getName());
//integer part first in reverse order
int result = Integer.compare(n2.getIntegerPart(), n1.getIntegerPart());
if (result != 0) {
return result;
}
//decimal part second, if integer parts were equal
return Integer.compare(n2.getDecimalPart(), n1.getDecimalPart());
}
private MyDecimal extractNumber(String name) {
try {
int s = name.lastIndexOf('_') + 1;
int e = name.lastIndexOf('.');
String number = name.substring(s, e);
String[] parts = number.split("\\.");
return new MyDecimal(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
} catch (Exception e) {
return new MyDecimal(0, 0);
}
}
});
System.out.println(Arrays.toString(fileNames));
}
}
Prints - [Release_Notes_CNV_23.5.pdf, Release_Notes_CNV_22.12.pdf, Release_Notes_CNV_22.9.pdf, Release_Notes_CNV_22.3.pdf].
My assignment is:
Create a file that has 2 columns of numbers: Distance and Speed.
Write a class TravelInfo which has three pieces of information: Speed, Time, Distance.
The class should also have a method calcTime() which calculates the time it will take to reach a destination based on the distance and speed (recall: Time = Distance/Speed)
Write a main program that:
Creates an ArrayList of TravelInfo objects of size 10.
Prompts the user for the name of the file and reads the data into TravelInfo objects
Calls the calcTime() method on each TravelInfo object.
Creates an output file with the data written in the format: Distance, Time, Speed
Every time I run my program I get an error
Exception in thread "main" java.util.NoSuchElementException
Other than this error I think I have done everything right except maybe calling my method, and I still haven't formatted the output file yet (not quite sure how). I can't continue while I get this error.
Here is my main() method:
public static void main(String[] args) throws IOException {
Scanner keyboard = new Scanner(System.in);
ArrayList<TravelInfo> list = new ArrayList<>();
System.out.println("What is the name of the file?");
String filename = keyboard.nextLine();
File f = new File(filename);
Scanner inputFile = new Scanner(f);
while(inputFile.hasNext()) {
int s = inputFile.nextInt();
int d = inputFile.nextInt();
int t = inputFile.nextInt();
TravelInfo p = new TravelInfo(s, d, t);
list.add(p);
TravelInfo cls = new TravelInfo(s,d,t);
cls.calcTime(t);
cls.calcTime(s);
cls.calcTime(d);
// System.out.println("Time is " + cls.calcTime(t));
/*for(int i=0; i<list.size(); i++) {
list.get(i).print();
*/ }
for(TravelInfo k : list)
System.out.println(k);
PrintWriter outputFile = new PrintWriter("Data.txt");
outputFile.println(list);
//outputFile.println();
outputFile.close();
}
}
And my TravelInfo class
public class TravelInfo {
private int speed;
private int distance;
private int time;
public TravelInfo(int s, int d, int t) {
speed = s;
distance = d;
time = t;
}
public int calcTime(int time) {
time = distance/speed;
return time;
}
}
You shall do some more validation, and never use the nextXXX() methods blindly - something like
while(true)
{
if (!inputFile.hasNextInt()) {
System.err.println("Reading file failed - invalid format (s)");
break;
}
int s = inputFile.nextInt();
System.out.println("Reading s = " + s);
if (!inputFile.hasNextInt()) {
System.err.println("Reading file failed - invalid format (d)");
break;
}
int d = inputFile.nextInt();
System.out.println("Reading d = " + d);
if (!inputFile.hasNextInt()) {
System.err.println("Reading file failed - invalid format (t)");
break;
}
int t = inputFile.nextInt();
System.out.println("Reading t = " + t);
// Do some stuff
}
This way, you will avoid the NoSuchElementException, and the application will terminate gracefully. You will get the debugging output on the console. It will also print out what exactly has been read from the file.
As Dorian said, you're missing some validation:
while(inputFile.hasNext()) // Tells you there is "at least" 1 more element.
{
int s = inputFile.nextInt(); // Good
int d = inputFile.nextInt(); // Not good if 's' has taken the last element
int t = inputFile.nextInt(); // Same as above
// rest of the code here...
}
I personnally don't like the 'while(true)' stuff, so here is my version.
while(inputFile.hasNextInt()) // I would use 'hasNextInt()' rather than 'hasNext()'
// This will make sure the next data can be cast to an Integer
{
Integer d = null;
Integer t = null;
Integer s = inputFile.nextInt();
if( inputFile.hasNextInt() {
d = inputFile.nextInt();
if( inputFile.hasNextInt() {
t = inputFile.nextInt();
}
}
// 's' will never be null.
if( d != null && t != null ) {
TravelInfo p = new TravelInfo(s, d, t);
list.add(p);
TravelInfo cls = new TravelInfo(s,d,t);
cls.calcTime(t);
cls.calcTime(s);
cls.calcTime(d);
// System.out.println("Time is " + cls.calcTime(t));
/*for(int i=0; i<list.size(); i++)
{
list.get(i).print();
*/ }
for(TravelInfo k : list)
System.out.println(k);
PrintWriter outputFile = new PrintWriter("Data.txt");
outputFile.println(list);
//outputFile.println();
outputFile.close();
}
else if( inputFile.hasNext()) {
// At this point, you there the remaining data cannot be safely cast to an Integer.
}
else {
// Not enough data to process.
}
}
public class TravelInfo {
private int speed;
private int distance;
private int time;
public TravelInfo(int s, int d, int t) {
speed = s;
distance = d;
time = t;
}
public int calcTime(int time) {
time = distance/speed;
return time;
}
// Override toString() instead of using the default Object.toString()
#Override
public String toString() {
// Return whatever 'String' you want
return String.format( "%d, %d, %d", speed, distance, time );
}
}
I had previously written code that would take a mathematical expression and turn it into a parse tree, I am now trying to visually display the tree that has been created by drawing on a JPanel. The expression is input into the console by the user, it outputs the postfix and I want to also display the tree. However when I run my current program the tree is not rendered on the JPanel. I don't get any errors from the compiler so I'm unsure what the issue is.
public class TreeView extends JPanel {
//Class for drawing the Tree onto a panel
private int radius = 20;
private int levelGap = 50;
ExpTree t;
public TreeView(ExpTree t) {
this.t = t;
}
protected void paintComponent(Graphics g) {
super.paintComponents(g);
if (t.getRoot() != null) {
displayTree(g, t.getRoot(), getWidth() / 2, 30, getWidth() / 4);
}
}
private void displayTree(Graphics g, ExpTree t, int x, int y, int gap) {
g.drawOval(x - radius, y - radius, 2 * radius, 2 * radius);
g.drawString(t.getLeafVal() + "", x - 6, y + 4);
if (t.getlChild() != null) {
connectCircles(g, x - gap, y + levelGap, x, y);
displayTree(g, t.lChild, x - gap, y + levelGap, gap /2);
}
if (t.getrChild() != null) {
connectCircles(g, x + gap, y + levelGap, x, y);
displayTree(g, t.rChild, x + gap, y + levelGap, gap /2);
}
}
private void connectCircles(Graphics g, int x1, int y1, int x2, int y2) {
double d = Math.sqrt(levelGap * levelGap + (x2 - x1) * (y2 - y1));
int x11 = (int)(x1 - radius * (x1 - x2) / d);
int y11 = (int)(y1 - radius * (y1 - y2) / d);
int x21 = (int)(x2 + radius * (x1 - x2) / d);
int y21 = (int)(y2 + radius * (y1 - y2) / d);
g.drawLine(x11, y11, x21, y21);
}
}
public class Test extends JFrame {
public Test() {
setSize(400, 400);
setLayout(new BorderLayout());
JPanel jp = new JPanel();
add(jp);
setVisible(true);
}
public static void main(String[] args) {
Test test = new Test();
//create parse trees from input in console
boolean done = false;
boolean valid = false;
Parser p = new Parser();
ExpTree myTree;
System.out.println("Enter an expression to convert into postfix notation");
do {
System.out.println("Enter an expression: ");
try {
myTree = p.parseLine();
}
catch (ParseException e) {
System.out.println("Invalid Expression: Ensure it ends with a semicolon");
continue;
}
System.out.println(myTree.toPostfix(myTree));
TreeView view = new TreeView(myTree);
test.add(view);
view.repaint();
System.out.println("Do you want to enter another expression? (y/n)");
do {
String s = p.getLine();
switch (s) {
case "y" : valid = true;
done = false;
continue;
case "n" : valid = true;
done = true;
continue;
default: valid = false;
done = false;
System.out.println("Invalid input: Must be y or n");
}
} while (!valid);
} while (!done);
}
}
//Setup of the tree incase it's useful
public class ExpTree {
//Tree object that is created when an expression is parsed
private int type;
private Object leafVal;
public ExpTree lChild, rChild;
public static final int NUM = 0, VAL = 1, OP = 2;
private StringBuffer sb = new StringBuffer();
public ExpTree(int type, Object leafVal, ExpTree l, ExpTree r) {
this.type = type;
this.leafVal = leafVal;
this.lChild = l;
this.rChild = r;
}
//return the forth expression, a postfix expression
public String toPostfix(ExpTree t) {
if (t != null) {
toPostfix(t.lChild);
toPostfix(t.rChild);
sb.append(t.leafVal);
sb.append(" ");
}
return sb.toString();
}
public ExpTree getRoot() {
return this;
}
public Object getLeafVal() {
return leafVal;
}
public ExpTree getlChild() {
return lChild;
}
public ExpTree getrChild() {
return rChild;
}
}
class ParseException extends RuntimeException
{ public ParseException(String s)
{ super("Invalid expression: "+s);
}
}
public class Parser
{ private Lexer lex;
public Parser()
{ lex = new Lexer();
}
public ExpTree parseLine()
{ lex.init();
lex.getToken();
ExpTree result = parseExp(true);
if (lex.token==Lexer.where)
{ lex.getToken();
ExpTree defs = parseDefList();
result = makeWhereTree(result, defs);
}
if (lex.token!=Lexer.semico)
{ throw new ParseException("semicolon expected");
}
return result;
}
public String getLine()
{ return lex.getLine();
}
private ExpTree parseExp(boolean idsAllowed)
{ ExpTree result = parseTerm(idsAllowed);
{ while (lex.token==Lexer.plus || lex.token==Lexer.minus)
{ int op = lex.token;
lex.getToken();
if (op==Lexer.plus)
result = makePlusTree(result, parseTerm(idsAllowed));
else
result = makeMinusTree(result, parseTerm(idsAllowed));
}
}
return result;
}
private ExpTree parseTerm(boolean idsAllowed)
{ ExpTree result = parseOpd(idsAllowed);
{ while (lex.token==Lexer.times || lex.token==Lexer.div || lex.token==Lexer.mod)
{ int op = lex.token;
lex.getToken();
if (op==Lexer.times)
result = makeTimesTree(result, parseOpd(idsAllowed));
else if (op==Lexer.mod)
result = makeModTree(result, parseOpd(idsAllowed));
else
result = makeDivideTree(result, parseOpd(idsAllowed));
}
}
return result;
}
private ExpTree parseOpd(boolean idsAllowed)
{ ExpTree result;
switch(lex.token)
{ case Lexer.num:
result = makeNumberLeaf(lex.numval);
lex.getToken();
return result;
case Lexer.id:
if (!idsAllowed)
throw new ParseException("identifier not allowed in identifier defintion");
result = makeIdLeaf(lex.idval);
lex.getToken();
return result;
case Lexer.lp:
lex.getToken();
result = parseExp(idsAllowed);
if (lex.token!=Lexer.rp)
throw new ParseException("right parenthesis expected");
lex.getToken();
return result;
default:
throw new ParseException("invalid operand");
}
}
private ExpTree parseDefList()
{ ExpTree result = parseDef();
while (lex.token==Lexer.and)
{ lex.getToken();
result = makeAndTree(result, parseDef());
}
return result;
}
private ExpTree parseDef()
{ if (lex.token!=Lexer.id)
throw new ParseException("definition must start with identifier");
char id = lex.idval;
if (Character.isUpperCase(id))
throw new ParseException("upper-case identifiers cannot be used in defintion list");
lex.getToken();
if (lex.token!=Lexer.eq)
throw new ParseException("'=' expected");
lex.getToken();
return makeDefTree(id, parseExp(false));
}
// the next seven methods need to be modified for part 3 of the assignment
static ExpTree makeNumberLeaf(int n)
{ return new ExpTree(ExpTree.NUM, n, null, null);
// this method should return a new number leaf with value n created using your constructor
// if you've used the abstract class approach you will probably need something like
// return new NumLeaf(n);
// if you've used an ExpTree class that stores the node kind you will probably need something like
// return new ExpTree(ExpTree.numNode, n , null, null);
}
static ExpTree makeIdLeaf(char c)
{ return new ExpTree(ExpTree.VAL, c, null, null);
// this method should return a new id leaf with value c
}
static ExpTree makePlusTree(ExpTree l, ExpTree r)
{ return new ExpTree(ExpTree.OP, '+', l, r);
// this method should return a new plus node with children l and r created using your constructor
// if you've used the abstract class approach you will probably need something like
// return new OpNode('+', l, r);
// or
// return new PlusNode(l, r);
// if you've used an ExpTree class that stores the node kind you will probably need something like
// return new ExpTree(ExpTree.opMode, '+', l, r);
}
static ExpTree makeMinusTree(ExpTree l, ExpTree r)
{ return new ExpTree(ExpTree.OP, '-', l, r);
// this method should return a new minus node with children l and r
}
static ExpTree makeTimesTree(ExpTree l, ExpTree r)
{ return new ExpTree(ExpTree.OP, '*', l, r);
// this method should return a new times node with children l and r
}
static ExpTree makeDivideTree(ExpTree l, ExpTree r)
{ return new ExpTree(ExpTree.OP, '/', l, r);
// this method should return a new divide node with children l and r
}
static ExpTree makeModTree(ExpTree l, ExpTree r)
{ return new ExpTree(ExpTree.OP, '%', l, r);
// this method should return a new mod (%) node with children l and r
}
// the next three methods need to be modified for part 6 of the assignment - do not modify them if you have not attempted part 6
static ExpTree makeWhereTree(ExpTree l, ExpTree r)
{ // remove the following line if you modify this method; leave it here if you do not attempt part 6
System.out.println("Part 6 not attempted");
return null;
// this method should return a new 'where' node with children l and r
}
static ExpTree makeAndTree(ExpTree l, ExpTree r)
{ return null;
// this method should return a new 'and' node with children l and r
}
static ExpTree makeDefTree(char c, ExpTree t)
{ return null;
// this method should return a new definition node with identifier c and child t
// if your definition nodes have 2 children you should put a new id leaf in the left child and use t as the right child
}
}
class Lexer
{ static final int err = 0, num = 1, id = 2, plus = 3, minus = 4, times = 5, div = 6, mod = 7,
lp = 8, rp = 9, semico = 10, where = 11, and = 12, eq = 13;
int token;
char idval;
int numval;
private String line = "";
private BufferedReader buf;
Lexer()
{ buf = new BufferedReader(new InputStreamReader(System.in));
}
void init()
{ do
try
{ line = buf.readLine().trim();
}
catch(Exception e)
{ System.out.println("Error in input");
System.exit(1);
}
while (line.length()==0);
}
String getLine()
{ init();
return(line);
}
void getToken()
{ if (line.length()==0)
token = err;
else switch (line.charAt(0))
{ case '+':
token = plus;
line = line.substring(1).trim();
break;
case '-':
token = minus;
line = line.substring(1).trim();
break;
case '*':
token = times;
line = line.substring(1).trim();
break;
case '/':
token = div;
line = line.substring(1).trim();
break;
case '%':
token = mod;
line = line.substring(1).trim();
break;
case '(':
token = lp;
line = line.substring(1).trim();
break;
case ')':
token = rp;
line = line.substring(1).trim();
break;
case ';':
token = semico;
line = line.substring(1).trim();
break;
case '=':
token = eq;
line = line.substring(1).trim();
break;
default:
if (Character.isDigit(line.charAt(0)))
{ token = num;
numval = line.charAt(0) - '0';
int i = 1;
while (i<line.length()&&Character.isDigit(line.charAt(i)))
{ numval = numval*10+line.charAt(i)-'0';
i++;
}
line = line.substring(i).trim();
}
else if (Character.isLowerCase(line.charAt(0)))
{ char c = line.charAt(0);
if (c=='w' && line.length()>=5 && line.charAt(1)=='h' && line.charAt(2)=='e' && line.charAt(3)=='r' &&
line.charAt(4)=='e')
{ token = where;
line = line.substring(5).trim();
}
else if (c=='a' && line.length()>=3 && line.charAt(1)=='n' && line.charAt(2)=='d')
{ token = and;
line = line.substring(3).trim();
}
else if (line.length()>1 && Character.isLetter(line.charAt(1)))
{ token = err;
}
else
{ token = id;
idval = c;
line = line.substring(1).trim();
}
}
else
token = err;
}
}
}
Oh, long ago, that I made swing stuff.
In Test.main, if I replace
System.out.println(myTree.toPostfix(myTree));
TreeView view = new TreeView(myTree);
test.add(view);
view.repaint();
with:
System.out.println (myTree.toPostfix(myTree));
TreeView view = new TreeView(myTree);
test.add (view);
// view.repaint();
test.invalidate ();
I get a somehow splittet graph - probably a step to begin with.
4+2*3-9*4+2*3-9;
4 2 3 * + 9 4 * - 2 3 * + 9 -
But only after going to fullsize. Resizing demolates the graphic and the program hangs.
2 additional improvements, one critical, one user friendlyness:
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
should be added to the CTor
public Test() {
before setVisible, so you don't have to stop the Program with Ctrl-C. That was the critical one.
The second is in the lexer. If you test the input after trimming on line.endsWith (";"), you may add the semicolon silently yourself, instead of telling the user, what and how to do it.
Even better: Add a JTextField at BorderLayout (NORTH) or SOUTH, for the formula, so that the user may update it. For testing purpose it would be nice to prefill it.
Update
I meanwhile had fun, improving it, which might be mostly a question of taste and priorities, but maybe you're interested. And one step is most probably better, than the invalidate-command above.
here are the needed imports:
import javax.swing.*;
import java.awt.*;
import java.io.*;
import javax.swing.border.*;
Here the TestTreeView (I have way to much classes called 'Test'):
public class TestTreeView extends JFrame {
JTextField jtf = new JTextField (30);
JButton jb = new JButton ("go!");
public TestTreeView () {
setSize (900, 600); // a
Container cp = getContentPane (); // b
JPanel jp = new JPanel ();
jp.setLayout (new BorderLayout());
cp.add (jp);
jp.setBorder (BorderFactory.createEtchedBorder ()); // c
JPanel tp = new JPanel ();
tp.setLayout (new FlowLayout ());
tp.add (jtf);
jtf.setText ("1+2*3/4%5");
jtf.setFont ((jtf.getFont()).deriveFont (24.0f)); // I like big fonts, maybe need stronger glasses :)
tp.add (jb);
jp.add (tp, BorderLayout.NORTH);
actions (jp); // see below
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setVisible (true);
}
public void actions (JPanel jp) {
jb.addActionListener (ae -> {
String s = jtf.getText ();
System.out.println (s);
if (s.length () > 1) {
//create parse trees from input in JTextField
Parser p = new Parser (s); // redefined, see below
ExpTree myTree;
try {
myTree = p.parseLine ();
System.out.println (myTree.toPostfix(myTree));
TreeView view = new TreeView (myTree);
jp.add (view, BorderLayout.CENTER);
// view.repaint();
// jp.invalidate ();
jp.revalidate (); // c
}
catch (ParseException e) {
System.out.println ("Invalid Expression: Ensure it ends with a semicolon");
}
}
});
}
public static void main (String[] args) {
TestTreeView test = new TestTreeView ();
}
}
Remarks:
a) I need more space, hence 900x600
b) At least to Java-1.5, you shouldn't add to the main Frame, but to the contentPane. Maybe it changed with 1.6, 1.7 or 1.8
c) revalidate is the way to go. Paints right up front, not just after first resize. This should apply, even if you don't like to use JTextField and button.
Parser found a new CTor, which expects a String, we pass from the JTextField:
class Parser
{
private Lexer lex;
public Parser()
{
lex = new Lexer();
}
public Parser (String s)
{
lex = new Lexer (s);
}
and Lexer found a new CTor, which expects a String, which is passed from the Parser:
class Lexer
void init()
{
do
try
{
line = buf.readLine ().trim ();
if (! line.endsWith (";"))
line = String.format ("%s;", line);
}
catch(Exception e)
{
System.out.println("Error in input");
System.exit (1);
}
while (line.length () == 0);
}
{
// ...
Lexer ()
{
buf = new BufferedReader (new InputStreamReader(System.in));
}
Lexer (String s)
{
buf = new BufferedReader (new StringReader (s));
}
// plus the automatic semicolon healing:
void init()
{
do
try
{
line = buf.readLine ().trim ();
if (! line.endsWith (";"))
line = String.format ("%s;", line);
}
catch(Exception e)
{
System.out.println("Error in input");
System.exit (1);
}
while (line.length () == 0);
}
Last famous words. In the net, there are a lot tutorials, how to detach the work of actions like in the ActionListener from the main event loop. You should consider working through such material. This code here is not state of the art. :)
[Hi, guys. I'm learning Java with Cay Horstmann's 'Java SE8 for the Really Impatient'. Studying chapter 4]
I want to call the toString() method of the parent class and add something to it. Unfortunately, the call to the toString() method of the parent class seems not to be working.
So far I've got these classes:
public class Point {
private double _x = 0;
private double _y = 0;
public Point(double x, double y) {
_x=x;
_y=y;
}
#Override
public String toString() {
String theString = getClass().getSuperclass().toString() + " => " + getClass().getCanonicalName();
theString += "[";
int i=0;
for (Field theField : getClass().getDeclaredFields()) {
theField.setAccessible(true);
try {
if (i>0) theString += ", ";
theString += theField.getName() + ": " + theField.get(this).toString();
i++;
} catch (IllegalArgumentException ex) {
Logger.getLogger(Point.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("err1");
} catch (IllegalAccessException ex) {
Logger.getLogger(Point.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("err2");
}
}
theString += "]";
return theString;
}
...
}
public class LabeledPoint extends Point {
private String _label = "";
public LabeledPoint(String label, double x, double y) {
super(x, y);
this._label = label;
}
...
}
And I call them with this main method:
public static void main (String[] args) {
LabeledPoint lp1 = new LabeledPoint("FirstPoint", 10.5, 30);
System.out.println("The new point is:");
System.out.println(lp1);
}
So, I was expecting to get something like this:
Point[_x: 10.5, _y:30.0]=>LabeledPoint[_label: FirstPoint]
But instead, I'm getting :
Point=>LabeledPoint[_label: FirstPoint]
That is, the getClass().getSuperclass().toString() is not executing Point.toString(), but it's just printing out the canonical name.
Why is that?
You seem to need super.toString() instead of getClass().getSuperClass().toString()
OK, guys. (I don't know how good this is, but it works)
The Point class looks like this:
public class Point {
private double _x = 0;
private double _y = 0;
public Point(double x, double y) {
_x=x;
_y=y;
}
#Override
public String toString() {
String theString = super.toString() + "=>" + getClass().getCanonicalName();
//The following creates an array of fields that includes the parent 'Point's fields if the object is an instance of a direct child class of Point
Field[] theFields;
if (this.getClass() == Point.class) {
theFields = getClass().getDeclaredFields();
} else {
theFields = new Field[Point.class.getDeclaredFields().length+getClass().getDeclaredFields().length];
System.arraycopy(
Point.class.getDeclaredFields(),
0,
theFields,
0,
Point.class.getDeclaredFields().length
);
System.arraycopy(
getClass().getDeclaredFields(),
0,
theFields,
Point.class.getDeclaredFields().length,
getClass().getDeclaredFields().length
);
}
theString += "[";
int i=0;
for (Field theField : theFields) {
theField.setAccessible(true);
try {
if (i>0) theString += ", ";
theString += theField.getName() + ": " + theField.get(this).toString();
i++;
} catch (IllegalArgumentException ex) {
Logger.getLogger(Point.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("err1");
} catch (IllegalAccessException ex) {
Logger.getLogger(Point.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("err2");
}
}
theString += "]";
return theString;
}
...
}
I am trying to make a calculator that performs the quadratic formula.
Currently if my result would be a decimal it returns NaN. (EDIT: Resolved)
Preferably I would like the result to be in an simplified radical form (i.e. √(99) = 3√(11) ).
How would I go about achieving this?
This is what I have so far.
// Do the math
private double mathCalcPlus(double varA,double varB,double varC) {
return ((-varB + Math.sqrt(varB * varB - 4 * varA * varC)) / 2 * varA);
}
private double mathCalcMinus(double varA,double varB,double varC) {
return ((-varB - Math.sqrt(varB * varB - 4 * varA * varC)) / 2 * varA);
}
Any help will be greatly appreciated.
This works great! However, I decided to add the top bar of the radical sign just for fun :D
import java.util.Scanner;
public class Radical {
public static void main(String[] args) {
System.out.print("Enter the unsimplified radical: ");
Scanner scan = new Scanner(System.in);
int input = scan.nextInt();
recurse(input);
}
public static void recurse(int x) {
System.out.println(" ______");
System.out.println("Attempting to simplify -/" + x);
int a = 0;
int b = 0;
int count = 0;
for (int i = 1; i < x; i++) {
if ((i * (x/i)) == x) {
//System.out.println(i + "<i rest>" + (x/i));
a = i;
b = x/i;
if (Math.sqrt(a)%1==0) {
if (a != 1) {
System.out.println(" ______");
System.out.println(" " + (int)Math.sqrt(a) + "-/" + b);
count = 1;
}
}
}
}
if (count>0) {
recurse(b);
} else if (count==0) {
System.out.println(" ______");
System.out.println("Cannot simplify -/" + x);
}
}
}
Here's something that might help as far as simplifying radicals go. Give it the unsimplified radical (let's say 850) and it should return the correct answer (5-/34). It also tries to recursively simplify what's left in the radical in case it needs to be broken down again.
This was written quickly so I'm sure there are edge cases I missed that will throw off the calculations but I hope it helps at least a little. Best of luck!
import java.util.Scanner;
public class Radical {
public static void main(String[] args) {
System.out.print("Enter the unsimplified radical: ");
Scanner scan = new Scanner(System.in);
int input = scan.nextInt();
recurse(input);
}
public static void recurse(int x) {
System.out.println("Attempting to simplify -/" + x);
int a = 0;
int b = 0;
int count = 0;
for (int i = 1; i < x; i++) {
if ((i * (x/i)) == x) {
//System.out.println(i + "<i rest>" + (x/i));
a = i;
b = x/i;
if (Math.sqrt(a)%1==0) {
if (a != 1) {
System.out.println((int)Math.sqrt(a) + "-/" + b);
count = 1;
}
}
}
}
if (count>0) {
recurse(b);
} else if (count==0) {
System.out.println("Cannot simplify -/" + x);
}
}
}