Java: подпроцесс, который с помощью Scanner генерирует исключение NoSuchElementException
Извините за неловкий английский; Это не мой родной язык.
Я разрабатываю Online-Judge для использования в следующем семестре.
Это получит один файл.java от студента и скомпилирует его,
и запустите.class и протестируйте его с предопределенными тестовыми примерами профессора.
Но когда я отправляю java-файл ниже, Enter.java, возникает ошибка выполнения, и.java-файл оценивается как ExecutionError.
import java.util.Scanner;
public class Enter {
public static void main(String[] args) {
// TODO Auto-generated method stub
int i=0;
int max=0;
int min=10000000;
while(true)
{
System.out.print("Enter integer :");
Scanner input = new Scanner(System.in);
i = input.nextInt();
if(i==-1)
break;
else if(i>max)
{
max=i;
}
else if(i<min)
{
min=i;
}
}
System.out.printf("Smallest Integer is : %d",min);
System.out.println();
System.out.printf("Largest Integer is : %d", max);
}
}
Конечно, это не правильный исходный код, но я считаю, что система оценила его как ExecutionError (это означает, что возникает исключение, когда система запускает.class для проверки его с помощью testcases). И NoSuchElementException также происходит в input.nextInt(); Но он должен быть оценен как Fail(работает и заканчивается хорошо, но выдает неправильный вывод).
Вот источник JudgeModule.java
private Judgement judge() {
// some works before compile & test //
// phase 1. compile //
CompileResult compileResult = tester.doCompile(compiler, fd);
if( !compileResult.isSuccess() ) // compile fail
{
// some works
Judgement judgement = new Judgement(compileResult.getResult());
return judgement;
}
// pahse 2. execute
ExecuteResult executeResult = tester.doTest(compiler, fd, testcases);
if( executeResult.getException() != null )
{
// some works
Judgement judgement = new Judgement(executeResult.getResult());
return judgement;
}
// some works after compile & test//
Judgement judgement = new Judgement(executeResult.getResult());
return judgement;
}
tester является просто экземпляром SourcecodeTester, не имеет переменных-членов и просто содержит doCompile() и doTest().
Ниже приведен источник SourcecodeTester. Я опускаю doCompile() вещи.
public class SourcecodeTester {
static long executeTimeout = 1000;
public class ExecuteResult {
JudgeResult result;
Exception exception;
ArrayList<TestResult> testResults;
}
public class TestResult {
JudgeResult result;
Exception exception;
String output;
}
public ExecuteResult doTest(Compiler compiler, FileDescription fd, Testcase[] testcases )
{
// pahse 2. execute
JudgeResult result = JudgeResult.Pass;
Exception exception = null;
ArrayList<TestResult> testResults = new ArrayList<>();
try {
for( Testcase testcase : testcases )
{
testResults.add( execute(compiler, testcase, fd ) );
}
} catch( Exception e ) {
e.printStackTrace();
result = JudgeResult.SystemError;
exception = e;
}
// do some works
return new ExecuteResult(result, exception, testResults );
}
private TestResult execute(Compiler compiler, Testcase testcase, FileDescription fd )
{
Runtime runTime = Runtime.getRuntime();
String executeCommand = assembleExecuteCommand(compiler, fd);
JudgeResult executeResult = JudgeResult.Fail;
Exception executeException = null;
String executeOutput = "";
try {
boolean timeout = false;
long startTime = System.currentTimeMillis();
Process executeProcess = runTime.exec(executeCommand);
writeToProcessInput(executeProcess, testcase.getInput()); // write to process input
while( executeProcess.isAlive() && !timeout )
{
Thread.sleep(10);
if((System.currentTimeMillis()-startTime) > executeTimeout )
timeout = true;
}
if( timeout )
{
executeProcess.destroy();
throw new JudgeException("execution timeout!" + (System.currentTimeMillis()-startTime) + "ms", JudgeResult.ExecutionTimeout);
}
// exam exitValue
int exitValue = executeProcess.exitValue();
// read from process output
char[] processOutput = readFromProcessOutput(executeProcess);
// read from process error
char[] processError = readFromProcessError(executeProcess);
if( exitValue != 0 ) {
throw new JudgeException("execution fail with exitvalue : " + exitValue + " >\n" + String.valueOf(processError), JudgeResult.ExecutionError);
}
else if( processError.length != 0 ) {
throw new JudgeException("execution fail with error : " + String.valueOf(processError), JudgeResult.ExecutionError );
}
String output = String.valueOf(testcase.getOutput()).replaceAll("\r\n", "\n");
executeOutput = String.valueOf(processOutput);
if( Arrays.equals(processOutput, output.toCharArray()) ) {
executeResult = JudgeResult.Pass;
}
else {
executeResult = JudgeResult.Fail;
}
}
catch( JudgeException e ) {
e.printStackTrace();
executeResult = JudgeResult.ExecutionError;
executeException = e;
}
catch( Exception e ) {
e.printStackTrace();
executeResult = JudgeResult.SystemError;
executeException = e;
}
return new TestResult( testcase.getId(), executeResult, executeException, executeOutput );
}
private void writeToProcessInput(Process _process, char[] _dataToWrite ) throws IOException
{
OutputStreamWriter osw = new OutputStreamWriter(_process.getOutputStream() );
BufferedWriter writer = new BufferedWriter( osw );
writer.write( _dataToWrite );
// osw.write(_dataToWrite);
writer.close();
osw.close();
}
private char[] readFromProcessOutput(Process _process) throws IOException
{
return readFromStream( new InputStreamReader( _process.getInputStream() ) );
}
private char[] readFromProcessError(Process _process) throws IOException
{
return readFromStream( new InputStreamReader( _process.getErrorStream() ) );
}
private char[] readFromStream(InputStreamReader isr) throws IOException {
int numOfByteRead;
char[] readBuffer = new char[1024];
StringBuffer standardOutput = new StringBuffer();
while ((numOfByteRead = isr.read(readBuffer)) > 0) {
standardOutput.append(readBuffer, 0, numOfByteRead);
}
return standardOutput.toString().toCharArray();
}
}
Когда я компилирую и выполняю Enter.java из командной строки или Eclipse, он работает нормально, и я могу поставить несколько номеров из консоли, и исключений не возникает.
Но я отправляю его в OnlineJudge, и тогда возникает NoSuchElementException. Входной массив символов для тестирования просто содержит несколько чисел, разделенных пробелом.
Наконец, я хочу спросить,
В чем разница и как она работает по-разному между
- запускает Enter.class и печатает несколько входов из консоли.
- запускает Enter.class с помощью Process.exec() и записывает массив char в качестве входных данных в выходной поток подпроцесса.
Почему scanner.nextInt() в Enter.java генерирует исключение NoSuchElementException или нет?
Как я могу изменить OnlineJudge для Enter.java работает так же.