วันพุธที่ 22 สิงหาคม พ.ศ. 2555

ปัญหา JAVA การใช้ Method NextLine() ใน Scanner

บทความนี้เป็นการเปิดตัวบทความแรกที่เป็นเรื่องที่เกี่ยวข้องกับปัญหาของภาษา Java (ที่จริงเป็นปัญหาของตัวเองมากกว่า ภาษาเค้าน่าจะทำมาดีนะ คนอื่นเค้าใช้กันอาจจะไม่มีปัญหา 555+) โดยเจ้าปัญหาที่ว่านี้ เป็นปัญหาที่เกี่ยวกับเรื่องของการรับค่าจากคีย์บอร์ดที่เกิดจากการใช้คลาส Scanner (หาวิธีอยู่นานจะทำอย่างไรให้มันรับค่าได้อย่างแบบที่ต้องการ) ส่วนปัญหาที่ได้กล่าวมานี้จะเป็นอย่างไรนั้น มาติดตามกันเลย


ลองพิจารณาตัวอย่างโค๊ดด้านล่างนี้


import java.util.Scanner;

public class InputProblem {
    public static void main(String[] args) {

        int id;
        double salary;
        String name;

        // Create an object called in of Scanner class to read input.
        Scanner in = new Scanner(System.in);

        // Get the user's id
        System.out.print("Enter your id: ");
        id = in.nextInt();

        // Get the user's salary
        System.out.print("Enter your salary: ");
        salary = in.nextDouble();

        // Get the user's name
        System.out.print("Enter your name: ");
        name = in.nextLine();

        // Display the information
        System.out.println("Hello " + name + ". Your id is " + id +
                           " and your salary is " + salary);
    }
}

ผลลัพธ์จากการรันโปรแกรม InputProblem.java



อธิบายโปรแกรม

จากตัวอย่างการรันโปรแกรม เราจะเห็นว่าเมื่อเราป้อนเงินเดือน 50000.00 และกดเอ็นเทอร์ โปรแกรมจะข้ามการรับค่าในส่วนของ Enter your name ซึ่งปัญหานี้เนื่องมาจาก ความแตกต่างเล็กน้อยของเมธอด nextLine และเมธอดอื่นของคลาส Scanner เมื่อผู้ใช้กดคีย์ต่างๆ บนแป้นพิมพ์จะทำให้คีย์ที่ถูกกดนั้นถูกจัดเก็บไว้ในพื้นที่ของหน่วยความจำที่เราเรียกกันว่า คียบอร์ดบัฟเฟอร์ (ซึ่งมีลักษณะเป็นโครงสร้างแบบ queue หรือ FIFO ย่อมาจาก First-In-First-Out) เมื่อมีการกดปุ่มเอ็นเทอร์จะทำให้อักขระ \n ถูกจัดเก็บไว้ในบัฟเฟอร์ จากโค๊ดบรรทัดที่ 15 มีการร้องขอให้ผู้ใช้ป้อนตัวเลขจำนวนเต็ม เมื่อผู้ใช้กดเอ็นเทอร์ เมธอด nextInt จะอ่าน 1111 จากบัฟเฟอร์นั้น และหยุดอ่านเมื่อพบอักขระ \n ทำให้ \n ไม่ได้ถูกอ่านจากบัฟเฟอร์ขึ้นมาด้วย ซึ่งทำให้ \n นั้นยังคงค้างเติ่งอยู่ในบัฟเฟอร์นั้น พอโปรแกรมรันมาถึงโค๊ดบรรทัดที่ 19 สืบเนื่องมาจากที่ \n ยังคงค้างอยู่ในบัฟเฟอร์ แต่!!! เมธอด nextDouble ได้ถูกออกแบบมาให้มันข้ามการอ่าน \n ที่อยู่ตำแหน่งเริ่มแรกในบัฟเฟอร์ และอ่าน 50000.00 มาจากบัฟเฟอร์ และหยุดอ่านเมื่อพบกับ \n ที่มาจากการกดเอ็นเทอร์ เช่นเดียวกัน เมื่อป้อน 50000.00 แล้วกดเอ็นเทอร์ \n ก็ยังคงค้างเติ่งอยู่ในบัฟเฟอร์ ที่นี้มาถึงประเด็นสำคัญตรงบรรทัดที่ 23 เนื่องจากว่า เมธอด nextLine ไม่ได้ถูกออกแบบมาให้ข้ามการอ่าน \n ที่อยู่ ณ ตำแหน่งแรกเริ่มในบัฟเฟอร์ เมื่อเมธอด nextLine อ่านพบ \n ที่อยู่ ณ ตำแหน่งแรกเริ่มของบัฟเฟอร์ นั่นแสดงว่า ไม่มีอะไรจะให้มันอ่านค่าจากบัฟเฟอร์ หรือพูดได้อีกแบบว่าเป็นการสิ้นสุดการอ่านค่าจากบัฟเฟอร์นั้น ดังนั้นผู้ใช้จะไม่มีโอกาสได้ป้อนค่าที่ Enter your name เลยยยย วิธีการแก้ปัญหา วิธีที่ง่ายที่สุดคือ เพิ่มโค๊ด in.nextLine(); แทรกระหว่าง เมธอด nextDouble กับ เมธอด nextLine อ่านแล้วอาจจะงง แทรกตรงไหน มาดูตัวอย่างเลยดีกว่า 555+

import java.util.Scanner;

public class SolvedInputProblem {
    public static void main(String[] args) {

        int id;
        double salary;
        String name;

        // Create an object called in of Scanner class to read input.
        Scanner in = new Scanner(System.in);

        // Get the user's id
        System.out.print("Enter your id: ");
        id = in.nextInt();

        // Get the user's salary
        System.out.print("Enter your salary: ");
        salary = in.nextDouble();

        // To get rid of remaining newline in the buffer
        in.nextLine();

        // Get the user's name
        System.out.print("Enter your name: ");
        name = in.nextLine();

        // Display the information
        System.out.println("Hello " + name + ". Your id is " + id +
                           " and your salary is " + salary);
    }
}

บันทึกโปรแกรมชื่อ SolvedInputProblem.java จากนั้นทำการคอมไพล์และรันโปรแกรมจะได้ผลลัพธ์ ดังนี้



ที่มา : http://greenesses.blogspot.com/2011/01/java.html

ไม่มีความคิดเห็น:

แสดงความคิดเห็น