recently, i read in a book about passing a user defined class as an input to scanner but it didn't explained much about the logic behind it. here's the program
import java.nio.CharBuffer;
import java.util.Random;
import java.util.Scanner;
class ScannerInputBase implements Readable
{
private int count;
Random rand = new Random();
ScannerInputBase(int count) { this.count = count; }
public int read(CharBuffer cb) //read is a method in Readable interface
{
if(count-- == 0)
return -1;
for(int i=0;i<2;i++)
{ cb.append('a'); }
return 1;
}
}
public class ScannerInput {
public static void main (String args[]) {
Scanner input = new Scanner(new ScannerInputBase(5));
while(input.hasNext())
{
print(input.next()+"-");
}
}
}
and it's output is
aaaaaaaaaa-
i have 2 questions here
how read() function is getting called here?
i mean i understand it's implicitly geting called somehow but from where it's getting called.
a single hyphen in the output suggests that while loop in main function is iterated only once. but why only once. i was expecting output like aa-aa-aa-aa-aa-
how read() function is getting called here? i mean i understand it's
implicitly geting called somehow but from where it's getting called.
Answer lies in the source code of Scanner class for method next():
public String next() {
....
while (true) {
.....
if (needInput)
readInput();
...
}
}
Which takes us to readInput method which is defined as follows:
private void readInput() {
......
try {
n = source.read(buf);
} catch (IOException ioe) {
.....
}
.....
}
We see that readInput method is calling the read method of source object which is instance of Reader class and is passed as an argument to the Scanner constructor during Scanner's object creation.
Now, Since you have passed the object of subclass of Reader as an argument to the Scanner constructor. And also, You have overridden the read(CharBuffer) method witin your class, So
the overridden version of read method is being called by the Scanner.readinput method.
A single hyphen in the output suggests that while loop in main function is iterated only once. but why only once. I was expecting output like aa-aa-aa-aa-aa-
Because , there is no whitespace in the string aaaaaaaaaa which is the default delimiter Pattern. Consequenty, all string is read in single iteration. So, hasNext is returning false after first iteration and the while loop terminates.
Note: Always use #Override annotation while overriding a method
within subclass.
Scanner class is a wrapper class around streams to read and write data. It has a few overloaded constructors. In your case:
public Scanner(Readable source) {
this(source, WHITESPACE_PATTERN);
}
is invoked. Because interface Readable has only one method read(CharBuffer cb), ScannerInputBase is an instaceof Readable, so the Scanner object just invokes the read() method of whatever Readable is passed.
On the second point, look at the documentation of next()
Finds and returns the next complete token from this scanner. A
complete token is preceded and followed by input that matches the
delimiter pattern. This method may block while waiting for input to
scan, even if a previous invocation of hasNext() returned true.
The default pattern used is :
Pattern WHITESPACE_PATTERN = Pattern.compile(
"\\p{javaWhitespace}+");
SO, it your scanner's next() call, reads everything in just one go by making multiple read()calls.
Related
I've been teaching myself Java with http://www.cs.princeton.edu/courses/archive/spr15/cos126/lectures.html as a reference. They have a library called algs4 and it has several classes including StdIn, which I'm trying to implement below.
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
public class Tired
{
public static void main(String[] args)
{
//I thought this while statement will ask for an input
//and if an input is provided, it would spell out each character
while (!StdIn.hasNextChar()) {
StdOut.print(1); //seeing if it gets past the while conditional
char c = StdIn.readChar();
StdOut.print(c);
}
}
}
//This is from StdIn class. It has a method called hasNextChar() as shown below.
/*
public static boolean hasNextChar() {
scanner.useDelimiter(EMPTY_PATTERN);
boolean result = scanner.hasNext();
scanner.useDelimiter(WHITESPACE_PATTERN);
return result;
}
*/
If i run the code, it does ask for an input, but regardless of what i type in, nothing happens and nothing gets printed out.
I see that even StdOut.print(1); doesnt get printed out, so for some reason, it just gets stuck on while
It looks like the issue is with the condition for your while loop:
!StdIn.hasNextChar()
This says to continue as long as there isn't a next char. But you want to continue while there is one, so get rid of that ! and you should be good.
Here is some alternative code that works similarly. Not the best coding but works.
import java.util.Scanner;
public class test{
static Scanner StdIn = new Scanner(System.in);
static String input;
public static void main(String[] args){
while(true){
if(input.charAt(0) == '!'){ // use ! to break the loop
break;
}else{
input = StdIn.next(); // store your input
System.out.println(input); // look at your input
}
}
}
}
I have a problem creating a student class which contains a constructor which takes a Scanner string of a format "Brookes 00918 X12 X14 X16 X21". The conditions should be that there should be a student name and student number and the course codes should start with an "X". I have thrown IncorrectFormatExceptions in the case that they are not satisfied. However when I create a test class and enter a string and press enter , for example "abc 123" it doesn't produce an output which is usually the case.
Update: I've changed the code to use a String array tokens however now with the toString() method using "123 abc X12" it gives a Null Pointer Exception. It works when I put "123 abc" in the constructor
Update:Seems to work now forgot to initialize the arrayList
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Student extends UniversityPerson{
private String studentNumber="";
private List<String> courses=new ArrayList<String>();
private String studentName="";
public int checkNoofletters(char[] chararray){
int noofletters=0;
for (char c:chararray){
if (Character.isLetter(c)){
noofletters++;
}
}
return noofletters;
}
public String courseListinStr(){
String stringo="";
for (String c:courses){
stringo+=c;
stringo+=" ";
}
return stringo;
}
public Student(Scanner scanner) throws IncorrectFormatException{
int studentNumberCount=0;
int studentNameCount=0;
Scanner s=scanner;
String input=s.nextLine();
String[] tokens=input.split("\\s");
for (int i=0; i<tokens.length; i++){
char[] chars=tokens[i].toCharArray();
if (checkNoofletters(chars)==chars.length){//if the number of letters is equal to the character length
if (studentNameCount==1){throw new IncorrectFormatException("Can only have 1 student name");}
studentNameCount++;
this.studentName=tokens[i];
continue;
}
if (tokens[i].matches("[0-9]+")){//add to the studentNumbers list
if (studentNumberCount==1){throw new IncorrectFormatException("Can only have 1 student number");}
studentNumberCount++;
this.studentNumber=tokens[i];
continue;
}
if (!tokens[i].startsWith("X")){
throw new IncorrectFormatException("Course code must start with an 'X'");
}
System.out.println(tokens[i]);
courses.add(tokens[i]);
}
if (studentNumber=="" || studentName==""){
throw new IncorrectFormatException("Must have 1 student Number and Student Name");
}
}
#Override
public String toString() {
//return String.format("%s %s", studentName,courseListinStr());
return String.format("Student: %s %s", studentName,studentNumber);
}
#Override
public boolean equals(Object o) {
// TODO Auto-generated method stub
return false;
}
}
The best way would be to do something like this:
Scanner s=scanner;
String input = s.nextLine();
String[] tokens=input.split("\\s");
Now you can test all your conditions:
if (tokens.size() < yourNumber) throw new Exception("add here");
if (tokens[2].charAt(0)!='X') throw new Exception("add here");
and so on; it should be rather easy to create your Student Object based on your requirements.
Your program is full of errors and I'll list some of them after answering why it doesn't print anything: if you dump all threads you'll see that the main thread is stuck at next(), which blocks until next token is available, and effectively never leaves the constructor of the first student
if (s.hasNextInt()){
studentNumbers.add(s.nextInt());
s.next();
continue; // <--------- this line
}
I think this is not the only error in your program, so maybe you'd better throw the entire parsing away and restart from scratch.
You should create exactly one Scanner object for each input stream, not one for parsed object
You should not pass the scanner to the Student constructor
You should not put any algorithm in a constructor: make a separate object instead
To simplify your program introduce a Parser class
public class Parser {
public Parser(Reader in) {}
public boolean hasNext() {}
public Student next() {}
}
and inside next() make the parser deal with entire lines (Scanner.hasNextLine and Scanner.nextLine()) instead of individual tokens, otherwise you'll have to define a custom protocol to mean EOR (end of record)
Dealing with lines is easier to think about, program and test. Once you have the full record, you can further tokenize it with a simple String.split(), or directly use regular expressions.
I didn't go through, your whole code. But, I would suggest you to use StringTokenizer or split function and store it in temp array. Then, traverse through your temp array and validate the data.
Okay not sure what is going on. I am using Java Reflection and iterating and inspecting methods of a particular class. Below is the following code I am using:
public void test(){
Class useCases = Car.class;
Method[] methods = useCases.getMethods();
Integer[] numbers = {2, 5};
String[] numberStrings = {"2", "5"};
for(int i=0; i<methods.length; i++){
try {
System.out.print(methods[i].getName());
Method method = useCases.getMethod(methods[i].getName(), new Class[]{String.class, Integer.class});
Object returnV = method.invoke(new Car(), numberStrings[i], numbers[i]);
System.out.print(returnV.toString() + "\n");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Car Class:
public String getNumber(String number, Integer times){
return times == 2 ? number : null;
}
public String getNumber1(String number, Integer times){
return times == 5 ? number : null;
}
It loops through fine printing out the first two methods and the return value fine, but then it continues and prints out a wait() and not sure why and I am getting the following error:
java.lang.NoSuchMethodException: sample.Car.wait(java.lang.String,
java.lang.Integer)
Any help as to why the loop does not end with just printing and returning the values for the only two methods in that Car class.
getMethods returns all public methods available for class, including the ones inherited like wait() toString() which as you see don't accept (String, Integer) arguments, which is why
useCases.getMethod(methods[i].getName(), new Class[]{String.class, Integer.class});
is not able to find wait(String, Integer).
To get only methods declared in Car class use getDeclaredMethods instead.
BTW: instead of
System.out.print(returnV.toString() + "\n");
which will throw NullPointerException on returnV.toString() if returnV will be null use
System.out.println(returnV); // also you don't need to explicitly add `\n`,
// use println will add used by current OS line
// separator for you automatically
Every Class is implicitly extending Object, so you get all methods containing in Object too.
I am trying to create a piece of code which will;
return true if given an int n, which is with in 10 of 100 or 200.
import java.util.Scanner;
class nearHundred{
public boolean nearHundred(int n){
Scanner input = new Scanner(System.in);
n = input.nextInt();
if(10>=Math.abs(100-n) || 10>=Math.abs(200-n)){
return true;
}
return false;
}
}
Where have I gone wrong?
From comments it looks like your main method is misplaced, wherever it is I hope it exists only once in a project. Call your class from that main() method, for example -
new nearHundred().nearHundred(100); // a call from main method
Now coming to your code there are several things to correct here. Your method should not take care about Scanner, its job is to take input and check for the logic.
For example;
public class Utils {
public static boolean isNearToHundered(int num) {
return Math.abs(num-100)<=10 || Math.abs(num-200)<=10;
}
}
Give the responsibility to main method for parsing the input, this is how it should work.
Now since I made method static, you can call like
Utils.isNearToHundred(105); // TRUE
Here is how the method should look:
public void mainMethod() {
Scanner input=new Scanner(System.in);
int val=input.nextInt();
boolean nearHundredBoolean=nearHundred(val);
//do something with nearHundredBoolean....
//Same logic, but passes the input to the method nearHundred
public boolean nearHundred(int n) {
if(Math.abs(100-n)<=10 || Math.abs(200-n)<=10)
return true;
else return false;
}
You should pass the value of the scanner input into this method's parameter requirement, instead of not using the parameter n in your current method. If there is a problem, it may be due to the 'input.nextInt()' method that overwrites the value of the parameter n.
LinkedList Iterator next() throwing NoSuchElementException even when called after hasNext() returning true.
Environment: Java 6 on Sun Solaris
Any idea why I'm hitting this exception on next() method call?
// lines is an instance of LinkedList
// writer is a FileWriter, Believe that is irrelevant to issue
while(lines.hasNext()){
int i = 0;
do {
writer.write(lines.next());
writer.newLine();
i++;
} while (lines.hasNext() && i < targetLineCount);
// Some more code...
}
Update with More Code
public class MyClass { // Only one instance of this class is used across application
private List<String> master = new LinkedList<String>();
// Other instance members to tune this instance behaviour
public MyClass(){
// Read Source & populate master
}
public boolean writeDataSlot(Writer writer, int targetLineCount){ // Can be called by different Threads
Ierator<String> lines = master.iterator();
while(lines.hasNext()){
int i = 0;
do {
writer.write(lines.next());
writer.newLine();
i++;
} while (lines.hasNext() && i < targetLineCount);
// Some more code to populate slot from different source.
}
}
}
Seems like a threading issue, as Axel pointed out.
What happens if you make this method synchronized ?
public synchronized boolean writeDataSlot(Writer writer, int targetLineCount)
I see these possibilities:
lines is used from another thread
lines.next() is called in // some more code...
lines is bound to another instance in // some more code...