Hengameh.Hoseini
یک شنبه 09 فروردین 1394, 11:34 صبح
سلام.
(من تقریبا تازه جاوا خوندن رو شروع کردم)
اکثر برنامه های جاوایی که روی اینترنت هست, به جای اسکنر از
Input Stream Reader و Buffered Reader
برای گرفتن ورودی از کاربر استفاده کردن
مثلا این برنامه:
http://www.java-examples.com/calculate-rectangle-perimeter-using-java-example
می دونم که روش اسکنر, روش جدید هست؛ و این که می دونم روش های دیگه هم برای گرفتن ورودی از کاربر هست.
خواستم بدونم بین برنامه نویس های حرفه ای, بین این دو تا روش, کدوم رایج تر و مقبول تره؟
ahmad.mo74
یک شنبه 09 فروردین 1394, 16:18 عصر
سلام
روش های مختلفی برای گرفتن ورودی از کاربر هست از جمله همین هایی که نام بردید. اما اینکه از کدوم و در چه شرایطی استفاده کنید بستگی به شما و نیازتون داره.
مثلا اگر میخواید بر روی ورودی ای که کاربر میده بیشترین کنترل رو داشته باشید و مثلا ورودی رو tokenize کنید یا از regex استفاده کنید و ... یا اینکه راحت از ورودی عدد بخونید و ... بهتره از Scanner استفاده کنید. در کل Scanner امکانات زیادی داره.
اما اگر میخواید از ورودی فقط String بخونید (به صورت خط به خط) و کاری به مسائل دیگه مثل خوندن عدد و ... ندارید، BufferedReader گزنیه مناسبیه (این به این معنی نیست که با BufferedReader نشه عدد خوند) . مزایای استفاده از BufferedReader اینه که این کلاس کار خوندن از ورودی رو به صرفه تر انجام میده (بخاطر وجود buffer) و همچنین thread-safe هست.
این کلاس ها تنها برای خوندن ورودی از کنسول نیستند و تقریبا برای هر نوع ورودی ای مثل فایل، سوکت، ... میشه ازشون استفاده کرد.
اگر میخواید هم از مزایای BufferedReader بهره ببرید و هم از امکانات فراوان Scanner استفاده کنید، میتونید BufferedReader رو به عنوان source به Scanner بدید تا Scanner بتونه ورودی رو از طریق BufferedReader بخونه.
یعنی :
Scanner scanner = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
روش های دیگه ای که برای خوندن از کنسول میشه ازشون استفاده کرد، مثل Console و حتی خود System.in که ساده ترین روش هست.
کلاس Console همیشه در دسترس نیست (مثلا تو eclipse) و بهتره موقعی که برنامتون رو از طریق cmd یا terminal اجرا میکنید ازش استفاده کنید.
ویژگی خوبی که Console داره امکان خوندن password از کنسول هست :
Console console = System.console();
console.readPassword();
در مورد System.in هم که یه InputStream هست و فقط میشه باهاش آرایه ای از byte خوند. مثلا :
public static void main(String[] args) throws IOException {
byte[] bytes = new byte[48];
System.in.read(bytes);
System.out.println(new String(bytes));
}
در نهایت من یه تست از Scanner و BufferedReader گرفتم (از فایل برای ورودی استفاده کردم) و به نظر میاد BufferedReader سرعت بیشتری داره :
import java.io.*;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
/**
* @author avb
*/
public class Test {
public static void main(String[] args) {
int it = 10000;
String fileName = "D:\\test.txt";
double bufferedReaderAvg, scannerAvg;
warmUp(it, fileName);
System.out.println();
double linesPerSec = testReadLinesPerSec(it, fileName, name -> {
int lines = 0;
try (FileInputStream fileInputStream = new FileInputStream(name);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
while (bufferedReader.readLine() != null) {
lines++;
}
} catch (IOException e) {
e.printStackTrace();
}
return lines;
});
System.out.println("BufferedReader + InputStreamReader + FileInputStream -> " + linesPerSec + " (line / sec)");
bufferedReaderAvg = linesPerSec;
linesPerSec = testReadLinesPerSec(it, fileName, name -> {
int lines = 0;
try (FileReader fileReader = new FileReader(name);
BufferedReader bufferedReader = new BufferedReader(fileReader)) {
while (bufferedReader.readLine() != null) {
lines++;
}
} catch (IOException e) {
e.printStackTrace();
}
return lines;
});
System.out.println("BufferedReader + FileReader -> " + linesPerSec + " (line / sec)");
bufferedReaderAvg += linesPerSec;
linesPerSec = testReadLinesPerSec(it, fileName, name -> {
int lines = 0;
try (FileInputStream fileInputStream = new FileInputStream(name);
Scanner scanner = new Scanner(fileInputStream)) {
while (scanner.hasNextLine()) {
scanner.nextLine();
lines++;
}
} catch (IOException e) {
e.printStackTrace();
}
return lines;
});
System.out.println("Scanner + FileInputStream -> " + linesPerSec + " (line / sec)");
scannerAvg = linesPerSec;
linesPerSec = testReadLinesPerSec(it, fileName, name -> {
int lines = 0;
try (FileReader fileReader = new FileReader(name);
Scanner scanner = new Scanner(fileReader)) {
while (scanner.hasNextLine()) {
scanner.nextLine();
lines++;
}
} catch (IOException e) {
e.printStackTrace();
}
return lines;
});
System.out.println("Scanner + FileReader -> " + linesPerSec + " (line / sec)");
scannerAvg += linesPerSec;
linesPerSec = testReadLinesPerSec(it, fileName, name -> {
int lines = 0;
try (FileInputStream fileInputStream = new FileInputStream(name);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
Scanner scanner = new Scanner(bufferedInputStream)) {
while (scanner.hasNextLine()) {
scanner.nextLine();
lines++;
}
} catch (IOException e) {
e.printStackTrace();
}
return lines;
});
System.out.println("Scanner + BufferedInputStream + FileInputStream -> " + linesPerSec + " (line / sec)");
scannerAvg += linesPerSec;
linesPerSec = testReadLinesPerSec(it, fileName, name -> {
int lines = 0;
try (FileInputStream fileInputStream = new FileInputStream(name);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
Scanner scanner = new Scanner(bufferedReader)) {
while (scanner.hasNextLine()) {
scanner.nextLine();
lines++;
}
} catch (IOException e) {
e.printStackTrace();
}
return lines;
});
System.out.println("Scanner + BufferedReader + InputStreamReader + FileInputStream -> " + linesPerSec + " (line / sec)");
scannerAvg += linesPerSec;
System.out.println();
System.out.println("Scanner Average Read Lines Per Second : " + (scannerAvg / 4));
System.out.println("BufferedReader Average Read Lines Per Second : " + (bufferedReaderAvg / 2));
}
interface ReadRunnable {
int readLines(String fileName);
}
private static void warmUp(int iteration, String fileName) {
ReadRunnable runnable = name -> {
try (FileInputStream fileInputStream = new FileInputStream(name)) {
byte[] bytes = new byte[2048];
while (true) {
if (fileInputStream.read(bytes) == -1) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return 0;
};
long start = System.currentTimeMillis();
for (int i = 0; i < iteration; i++) {
runnable.readLines(fileName);
}
System.out.println("Warm Up : " + (System.currentTimeMillis() - start) + " ms");
}
static double testReadLinesPerSec(int iteration, String fileName, ReadRunnable runnable) {
long lines = 0, start = System.nanoTime();
for (int i = 0; i < iteration; i++) {
lines += runnable.readLines(fileName);
}
return lines * TimeUnit.SECONDS.toNanos(1) / (double) (System.nanoTime() - start);
}
}
خروجی تست :
Warm Up : 1166 ms
BufferedReader + InputStreamReader + FileInputStream -> 1615903.5373240712 (line / sec)
BufferedReader + FileReader -> 1821731.489591279 (line / sec)
Scanner + FileInputStream -> 151491.21943727555 (line / sec)
Scanner + FileReader -> 151759.5795178512 (line / sec)
Scanner + BufferedInputStream + FileInputStream -> 151546.38366343756 (line / sec)
Scanner + BufferedReader + InputStreamReader + FileInputStream -> 151157.6425589665 (line / sec)
Scanner Average Read Lines Per Second : 151488.70629438272
BufferedReader Average Read Lines Per Second : 1718817.513457675
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.