我现在遇到这个问题解决问题(java的练习)。问题是要确保提供的输入的括号顺序正确(此链接中的更多信息:http://www.codeabbey.com/index/task_view/matching-brackets)。我遇到的问题是我的bufferedReader不会读取我的最后一行输入。它使它进入最后的循环,但似乎"暂停"在阅读之前。我能让它工作的唯一方法是按下回车键,然后程序继续通过input.readLine()最后一次并打印出我的字符串。这是我的代码:
public static void main(String[] args)
{
try
{
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input data:");
//First line is read to take in the number of lines for input will follow
int data = Integer.parseInt(input.readLine());
int i = 0;
while(i < data)
{
//temp string builder to hold the wanted characters
StringBuilder stringy = new StringBuilder();
String line = input.readLine();
//temp string builder holding the entire line
StringBuilder sb = new StringBuilder(line);
for(int j = 0; j < sb.length(); j++)
{
//loops through string builder & adds the wanted characters to stringy
switch(sb.charAt(j)){
case '(' : stringy.append(sb.charAt(j));
break;
case ')' : stringy.append(sb.charAt(j));
break;
case ']' : stringy.append(sb.charAt(j));
break;
case '[' : stringy.append(sb.charAt(j));
break;
case '{' : stringy.append(sb.charAt(j));
break;
case '}' : stringy.append(sb.charAt(j));
break;
}
}
System.out.println(stringy);
i++;
}
}catch(IOException x)
{
x.printStackTrace();
}
}
很抱歉,如果我不够清楚的话。我试图在网上阅读,但人们似乎没有这个具体问题。我不确定如何,但似乎在我的最后一行输入之前添加了额外的行或其他内容。感谢您的帮助,我真的很感激。
编辑: 对不起,我意识到我没有提供该程序的任何输入数据。这是:
4
(a+[b*c]-{d/3})
(a + [b * c) - 17]
((a * x) + [b] * y) + c
auf(zlo)men [gy<psy>] four{s}
只需将上述内容复制并粘贴到您的程序中,您就会看到问题
答案 0 :(得分:2)
BufferedReader#readLine
方法阻塞I / O读取输入,直到它在输入中找到行终止符。输入的最后一行与所有其他行不同,因为它的末尾没有行终止符。在终端中按Enter键会添加所需的行终止符字符,但作为副作用,它还会使终端将光标向下移动一行,从而导致&#34;之间的空格。你注意到的那些线条。这不是一个非常意外的行为,它不是代码中的错误,但您可以修复&#34;它通过确保在输入的最后一行末尾有一个行终止符。
我可以重现你描述的行为。我编译代码,运行它,然后粘贴样本输入。就像你说的那样,它挂在最后一行。我然后按回车键,这会导致它继续,但为什么这是必要的?在最后一次结果之前还有意想不到的差距。
> java Test
input data:
4
(a+[b*c]-{d/3})
(a + [b * c) - 17]
((a * x) + [b] * y) + c
auf(zlo)men [gy<psy>] four{s}([]{})
([)]
(()[])
()[]{}
我还注意到你没有提到的另一个问题。在上面示例的第七行(以&#34; auf&#34;开头的行)中,结果随后打印而不移动到新行。
嘿,这里发生了什么?好吧,让我们尝试应用一些调试技巧。 jstack是随JDK一起提供的工具,它允许您附加到正在运行的JVM并转储其执行线程的状态。这是一个很好的方式来了解代码在运行时的实际操作。当进程出现挂起时,让我们尝试正确运行jstack。首先,我需要确定JVM的进程ID。让我们使用jps来做到这一点。> jps
83518 Test
> jstack 83518
2015-12-24 21:25:17
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.65-b04 mixed mode):
...
"main" prio=5 tid=0x00007fbba2001000 nid=0x1903 runnable [0x000000010a560000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:272)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:273)
at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
- locked <0x00000007aaa9a5f0> (a java.io.BufferedInputStream)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
- locked <0x00000007aab2ad88> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
- locked <0x00000007aab2ad88> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at Test.main(Test.java:22)
...
我已经修剪了jstack的输出以显示相关的主线程。这很有趣。我可以看到主要的切入点:Test.main
。我可以看到对BufferedReader#readLine
的电话。在一系列其他方法调用之后,它将进入FileInputStream#read
。如果我多次运行jstack,我会看到同样的事情。这意味着执行卡在该方法中试图从输入读取字节。这很奇怪。有什么可以解释的?也许BufferedReader#readLine
的JavaDocs包含对行为的一些解释。
读取一行文字。一条线被认为是换行(&#39; \ n&#39;),回车(&#39; \ r&#39;)或回车后紧接着换行符中的任何一条终止
此时,让我们尝试形成一个假设。什么可能导致进程在尝试读取数据时遇到困难? JavaDocs说一条线被认为是由特定字符终止的。也许我们的最后一行输入并不包含行终止字符。
为了确认这个理论,让我们试着看看我们输入的hexadecimal转储。我通常使用xxd命令行工具来执行此操作。结果如下。
0000000: 340a 2861 2b5b 622a 635d 2d7b 642f 337d 4.(a+[b*c]-{d/3}
0000010: 2920 0a28 6120 2b20 5b62 202a 2063 2920 ) .(a + [b * c)
0000020: 2d20 3137 5d0a 2828 6120 2a20 7829 202b - 17].((a * x) +
0000030: 205b 625d 202a 2079 2920 2b20 630a 6175 [b] * y) + c.au
0000040: 6628 7a6c 6f29 6d65 6e20 5b67 793c 7073 f(zlo)men [gy<ps
0000050: 793e 5d20 666f 7572 7b73 7d y>] four{s}
我在使用单个控制字符LF(换行符)的Mac上进行测试,以指示新行。这在其他平台上可能有所不同。最值得注意的是,Windows使用一系列2个控制字符:CR / LF(回车/换行)。根据{{3}}标准,LF的ASCII代码是十六进制表示的0a。这显示在Unicode代码表中。回到我们的十六进制转储,我们可以看到0个字符出现4次,并注意到最后一行末尾没有0a字符。
这开始看起来像一个有前途的理论。我们还可以做些什么来验证它?感谢Basic Latin(ASCII),我们可以查看许多常见JDK类的源代码实现,包括BufferedReader
。让我们尝试一下OpenJDK的实现。这是一个非常棘手的循环,但最重要的是它跟踪&#34;行结束&#34;在名为eol
的变量中,该条件导致它在fill
方法中退出填充其内部缓冲区,而是将字符串返回给调用者。
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n') || (c == '\r')) {
eol = true;
break charLoop;
}
}
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar++;
if (c == '\r') {
skipLF = true;
}
return str;
}
好的,现在我确信了!让我们通过重复我们的原始测试来测试假设,但这一次让我们确保在最后一行的末尾有一个行终止符。复制粘贴输入的那个版本,我现在看到这些结果。
> java Test
input data:
4
(a+[b*c]-{d/3})
(a + [b * c) - 17]
((a * x) + [b] * y) + c
auf(zlo)men [gy<psy>] four{s}
([]{})
([)]
(()[])
()[]{}
那更像是它!