วิธีที่ดีในการห่อหุ้ม Integer.parseInt ()


93

ฉันมีโปรเจ็กต์ที่เรามักจะใช้Integer.parseInt()ในการแปลง String เป็น int เมื่อมีบางอย่างผิดพลาด (ตัวอย่างเช่นStringไม่ใช่ตัวเลข แต่เป็นตัวอักษรaหรืออะไรก็ตาม) วิธีนี้จะทำให้เกิดข้อยกเว้น อย่างไรก็ตามหากฉันต้องจัดการกับข้อยกเว้นในโค้ดของฉันทุกที่สิ่งนี้จะเริ่มดูน่าเกลียดอย่างรวดเร็ว ฉันต้องการใส่วิธีนี้ แต่ฉันไม่มีเงื่อนงำในการส่งคืนค่าที่สะอาดเพื่อแสดงว่าการแปลงผิดพลาด

ใน C ++ ฉันสามารถสร้างเมธอดที่ยอมรับตัวชี้ไปที่ int และปล่อยให้เมธอดนั้นส่งคืนจริงหรือเท็จ อย่างไรก็ตามเท่าที่ฉันรู้สิ่งนี้ไม่สามารถทำได้ใน Java ฉันยังสามารถสร้างออบเจ็กต์ที่มีตัวแปรจริง / เท็จและค่าที่แปลงแล้ว แต่ดูเหมือนจะไม่เหมาะเช่นกัน สิ่งเดียวกันนี้เกิดขึ้นกับมูลค่าทั่วโลกและสิ่งนี้อาจทำให้ฉันมีปัญหากับมัลติเธรด

มีวิธีที่สะอาดในการทำเช่นนี้หรือไม่?


ตัวละครในสตริงทั้งหมดจะต้องมีตัวเลขทศนิยมยกเว้นว่าตัวอักษรตัวแรก ... แทนที่จะจัดการข้อยกเว้นทุกที่ในโค้ดให้ตรวจสอบรูปแบบสตริงก่อนเรียกใช้เมธอดแยกวิเคราะห์
Lightman

เป็นไปไม่ได้เลยที่จะเขียน regex ที่จะจับภาพจำนวนเต็ม 32 บิตที่ลงชื่อที่ถูกต้องทั้งหมดและไม่มีค่าใดที่ไม่ถูกต้อง 2147483647 เป็นกฎหมายintในขณะที่ 2147483648 ไม่ใช่
Seva Alekseyev

คำตอบ:


142

คุณสามารถส่งคืนIntegerแทนการintกลับมาnullเมื่อการแยกวิเคราะห์ล้มเหลว

เป็นเรื่องน่าเสียดายที่ Java ไม่ได้จัดเตรียมวิธีการทำเช่นนี้หากไม่มีข้อยกเว้นเกิดขึ้นภายในคุณสามารถซ่อนข้อยกเว้นได้ (โดยการจับและส่งคืนค่าว่าง) แต่อาจเป็นปัญหาด้านประสิทธิภาพหากคุณแยกวิเคราะห์เป็นร้อย ๆ ข้อมูลที่ผู้ใช้ให้มาหลายพันบิต

แก้ไข: รหัสสำหรับวิธีการดังกล่าว:

public static Integer tryParse(String text) {
  try {
    return Integer.parseInt(text);
  } catch (NumberFormatException e) {
    return null;
  }
}

โปรดทราบว่าฉันไม่แน่ใจว่าสิ่งนี้จะทำอย่างไรถ้าtextเป็นโมฆะ คุณควรพิจารณาว่า - หากมันแสดงถึงจุดบกพร่อง (เช่นรหัสของคุณอาจส่งผ่านค่าที่ไม่ถูกต้องได้ดี แต่ไม่ควรผ่านค่าว่าง) ดังนั้นการโยนข้อยกเว้นก็เหมาะสม ถ้ามันไม่ได้แสดงถึงจุดบกพร่องคุณก็น่าจะส่งคืนค่าว่างเหมือนที่คุณทำสำหรับค่าอื่น ๆ ที่ไม่ถูกต้อง

เดิมคำตอบนี้ใช้ตัวnew Integer(String)สร้าง; ตอนนี้ใช้Integer.parseIntและปฏิบัติการชกมวย ด้วยวิธีนี้ค่าขนาดเล็กจะถูกบรรจุลงในIntegerวัตถุที่แคชไว้ทำให้มีประสิทธิภาพมากขึ้นในสถานการณ์เหล่านั้น


1
วิธีนี้ช่วยได้อย่างไร? ไซต์การโทรจะต้องการ: <b> temp = tryParse (... ); ถ้า (temp! = Null) {target = temp; } else {do ​​recovery action}; </b> โดยมีข้อยกเว้นการโยนที่เป็นไปได้ในส่วนการกู้คืน ในสูตรดั้งเดิมไซต์เรียกต้อง <b> ลองเป้าหมาย = (... ). parseInt; catch (... ) {do recovery action} </b> โดยมีข้อยกเว้นการโยนเล็กน้อยในการกู้คืนที่กำลังดำเนินการโดยเพียงแค่ลบประโยค catch วิธีการแก้ปัญหาที่นำเสนอนี้ทำให้เข้าใจง่ายขึ้นได้อย่างไร (มีเคล็ดลับมายากล) หรือลดจำนวนโค้ดลงด้วยวิธีใด?
Ira Baxter

15
โดยทั่วไปแล้วการตรวจสอบรหัสเพื่อตรวจสอบการnullอ้างอิงจะสะอาดกว่าการจัดการข้อยกเว้นเป็นประจำ
Adam Maras

มันจะสะอาดกว่าที่จะหลีกเลี่ยงการส่งค่า null เป็นค่า แต่กลับระบุว่ามีข้อผิดพลาดเกิดขึ้น ไม่ควรใช้ข้อยกเว้นสำหรับการควบคุมการไหล
Esko

2
@ สตีฟคูโอ: ทำไม? ประโยชน์อยู่ที่ไหน ทั้งคู่สร้างจำนวนเต็มใหม่ทุกครั้ง? ถ้ามีอะไรฉันอยากจะใช้ Integer.parseInt และปล่อยให้ autoboxing ดูแลมันเพื่อใช้ประโยชน์จากแคชสำหรับค่าเล็ก ๆ
Jon Skeet

1
@Vlasec และไม่ใช่แค่ทางเลือกเท่านั้น แต่ยังมีเวอร์ชันพิเศษสำหรับรุ่นดั้งเดิมเช่น OptionalInt
Joshua Taylor

37

คุณคาดหวังพฤติกรรมอะไรเมื่อไม่ใช่ตัวเลข?

ตัวอย่างเช่นหากคุณมักมีค่าเริ่มต้นที่จะใช้เมื่ออินพุตไม่ใช่ตัวเลขวิธีการเช่นนี้อาจเป็นประโยชน์:

public static int parseWithDefault(String number, int defaultVal) {
  try {
    return Integer.parseInt(number);
  } catch (NumberFormatException e) {
    return defaultVal;
  }
}

วิธีการที่คล้ายกันสามารถเขียนขึ้นสำหรับลักษณะการทำงานเริ่มต้นที่แตกต่างกันเมื่อไม่สามารถแยกวิเคราะห์อินพุตได้


29

ในบางกรณีคุณควรจะจัดการกับข้อผิดพลาดในการแยกวิเคราะห์เป็นสถานการณ์ที่ล้มเหลวอย่างรวดเร็ว แต่ในกรณีอื่น ๆ เช่นการตั้งค่าโปรแกรมฉันชอบที่จะจัดการกับการป้อนข้อมูลที่ขาดหายไปกับค่าเริ่มต้นโดยใช้Apache คอมมอนส์แลง 3 NumberUtils

int port = NumberUtils.toInt(properties.getProperty("port"), 8080);

เวลาส่วนใหญ่ที่คุณใช้ apache commons ในโปรเจ็กต์ของคุณอยู่แล้วเนื่องจากเหตุผลอื่น ๆ (เช่น StringUtils) นั่นจะเป็นประโยชน์
Ratata Tata

16

ในการหลีกเลี่ยงการจัดการข้อยกเว้นให้ใช้นิพจน์ทั่วไปเพื่อให้แน่ใจว่าคุณมีตัวเลขทั้งหมดก่อน:

//Checking for Regular expression that matches digits
if(value.matches("\\d+")) {
     Integer.parseInt(value);
}

ขอบคุณสำหรับคำตอบ. ฉันอ่านคำตอบส่วนใหญ่ในหน้านี้ฉันได้เขียนวิธีแก้ปัญหา try / catch เป็นการส่วนตัว อย่างไรก็ตามนี่คือปัญหาของฉันแม้ว่าจะมีขนาดเล็ก แต่ด้วยวิธีแก้ปัญหานั้น IDE ส่วนใหญ่จะสำลักกับการวิเคราะห์การไหลของโค้ดของคุณเมื่อคุณได้ลอง / จับภายในลูป นั่นเป็นเหตุผลที่วิธีแก้ปัญหาโดยไม่ต้องลอง / จับคือสิ่งที่ฉันต้องการ
victor n.

4
ระวัง. นิพจน์ทั่วไปที่ตรงกับจำนวนเต็มเริ่มต้นด้วย 0 ซึ่งจะทำให้เกิด NumberFormatException ลองดูสิ ^ (?: [1-9] \ d * | 0) $ จากstackoverflow.com/questions/12018479/…
Goose

5
นิพจน์ทั่วไปนี้จะไม่จัดการกับตัวเลขเชิงลบ
Brad Cupit

7
นอกจากนี้ยังไม่ครอบคลุมช่วงตัวเลขที่อยู่นอกขอบเขตจำนวนเต็ม
Mohammad Yahia

10

นอกจากนี้Ints.tryParse()ในฝรั่ง มันไม่ทิ้งข้อยกเว้นในสตริงที่ไม่ใช่ตัวเลข แต่จะโยนข้อยกเว้นในสตริงว่าง


4

หลังจากอ่านคำตอบของคำถามแล้วฉันคิดว่าการห่อหุ้มหรือห่อเมธอด parseInt นั้นไม่จำเป็นอาจจะไม่ใช่ความคิดที่ดีด้วยซ้ำ

คุณสามารถคืนค่า 'null' ตามที่ Jon แนะนำได้ แต่จะมากหรือน้อยแทนที่โครงสร้าง try / catch โดยการตรวจสอบค่า null มีความแตกต่างเล็กน้อยในพฤติกรรมหากคุณ 'ลืม' การจัดการข้อผิดพลาด: หากคุณไม่พบข้อยกเว้นจะไม่มีการมอบหมายและตัวแปรด้านซ้ายมือจะเก็บค่าเดิมไว้ หากคุณไม่ทดสอบค่าว่างคุณอาจโดน JVM (NPE)

คำแนะนำของหาวดูดีกว่าสำหรับฉันเพราะฉันไม่ชอบคืนค่าว่างเพื่อส่งสัญญาณข้อผิดพลาดหรือสถานะพิเศษบางอย่าง ตอนนี้คุณต้องตรวจสอบความเท่าเทียมกันของการอ้างอิงกับวัตถุที่กำหนดไว้ล่วงหน้าซึ่งบ่งบอกถึงปัญหา แต่ในขณะที่คนอื่นโต้แย้งถ้าคุณ 'ลืม' ตรวจสอบอีกครั้งและสตริงไม่สามารถแยกวิเคราะห์ได้โปรแกรมจะยังคงอยู่โดยมี int ที่ถูกรวมอยู่ภายในวัตถุ 'ERROR' หรือ 'NULL'

โซลูชันของ Nikolay นั้นมีการวางแนววัตถุมากขึ้นและจะทำงานร่วมกับเมธอด parseXXX จากคลาส Wrapper อื่น ๆ เช่นกัน แต่ในท้ายที่สุดเขาเพิ่งแทนที่ NumberFormatException ด้วยข้อยกเว้น OperationNotSupported - อีกครั้งคุณต้องลอง / จับเพื่อจัดการอินพุตที่แยกวิเคราะห์ไม่ได้

ดังนั้นข้อสรุปของฉันที่จะไม่ห่อหุ้มเมธอด parseInt ธรรมดา ฉันจะห่อหุ้มก็ต่อเมื่อฉันสามารถเพิ่มการจัดการข้อผิดพลาด (ขึ้นอยู่กับแอปพลิเคชัน) ได้เช่นกัน


4

คุณสามารถใช้สิ่งนี้:

public class Test {
public interface Option<T> {
    T get();

    T getOrElse(T def);

    boolean hasValue();
}

final static class Some<T> implements Option<T> {

    private final T value;

    public Some(T value) {
        this.value = value;
    }

    @Override
    public T get() {
        return value;
    }

    @Override
    public T getOrElse(T def) {
        return value;
    }

    @Override
    public boolean hasValue() {
        return true;
    }
}

final static class None<T> implements Option<T> {

    @Override
    public T get() {
        throw new UnsupportedOperationException();
    }

    @Override
    public T getOrElse(T def) {
        return def;
    }

    @Override
    public boolean hasValue() {
        return false;
    }

}

public static Option<Integer> parseInt(String s) {
    Option<Integer> result = new None<Integer>();
    try {
        Integer value = Integer.parseInt(s);
        result = new Some<Integer>(value);
    } catch (NumberFormatException e) {
    }
    return result;
}

}

ฉันชอบวิธีแก้ปัญหาของคุณโดยใช้รูปแบบบางที ฮามาก;)
rodrigoelp

1
โซลูชันนี้ล้าสมัยแล้วเนื่องจากมี java.util.Optional ตั้งแต่ Java 8 :)
Vlasec

2

คุณยังสามารถจำลองพฤติกรรม C ++ ที่คุณต้องการได้ง่ายๆ

public static boolean parseInt(String str, int[] byRef) {
    if(byRef==null) return false;
    try {
       byRef[0] = Integer.parseInt(prop);
       return true;
    } catch (NumberFormatException ex) {
       return false;
    }
}

คุณจะใช้วิธีการดังนี้:

int[] byRef = new int[1];
boolean result = parseInt("123",byRef);

หลังจากนั้นตัวแปรresultจะเป็นจริงถ้าทุกอย่างเป็นไปอย่างสมบูรณ์และbyRef[0]มีค่าที่แยกวิเคราะห์

โดยส่วนตัวฉันจะยึดติดกับการจับข้อยกเว้น


2

คำตอบที่ได้รับจาก Jon Skeet นั้นใช้ได้ แต่ฉันไม่ชอบให้nullวัตถุ Integer กลับคืนมา ฉันพบว่าสิ่งนี้สับสนในการใช้งาน เนื่องจาก Java 8 มีตัวเลือกที่ดีกว่า (ในความคิดของฉัน) โดยใช้OptionalInt:

public static OptionalInt tryParse(String value) {
 try {
     return OptionalInt.of(Integer.parseInt(value));
  } catch (NumberFormatException e) {
     return OptionalInt.empty();
  }
}

สิ่งนี้ทำให้ชัดเจนว่าคุณต้องจัดการกรณีที่ไม่มีค่า ฉันอยากจะเพิ่มฟังก์ชันประเภทนี้ลงในไลบรารี java ในอนาคต แต่ฉันไม่รู้ว่าจะเกิดขึ้นหรือไม่


2

หากคุณใช้ Java 8 ขึ้นไปคุณสามารถใช้ไลบรารีที่เพิ่งเปิดตัวได้: https://github.com/robtimus/try-parse มีการสนับสนุน int, long และ boolean ที่ไม่ต้องอาศัยการจับข้อยกเว้น ซึ่งแตกต่างจาก Ints.tryParse ของ Guava ที่ส่งกลับ OptionalInt / OptionalLong / Optional เหมือนกับในhttps://stackoverflow.com/a/38451745/1180351แต่มีประสิทธิภาพมากกว่า


1

Java ของฉันเป็นสนิมเล็กน้อย แต่ให้ฉันดูว่าฉันสามารถชี้คุณไปในทิศทางที่ถูกต้องได้หรือไม่:

public class Converter {

    public static Integer parseInt(String str) {
        Integer n = null;

        try {
            n = new Integer(Integer.tryParse(str));
        } catch (NumberFormatException ex) {
            // leave n null, the string is invalid
        }

        return n;
    }

}

หากมูลค่าคืนของคุณคือnullคุณมีมูลค่าไม่ถูกต้อง มิฉะนั้นคุณจะมีไฟล์Integer.


OP ต้องการผลลัพธ์การแปลง (เป็นข้อมูลอ้างอิง) บวกกับข้อบ่งชี้ว่าการแปลงสำเร็จ (หรือไม่)
หาว

1
@yawn: และการอ้างอิงเป็นโมฆะให้การบ่งชี้นั้นอย่างแน่นอน
Jon Skeet

@ John Skeet: ถูกต้อง แต่ฉันอ่านเจตนาของเขาต่างออกไป เขาเขียนบางอย่างเช่นการใช้วัตถุกลางเพื่อแยกความแตกต่างระหว่างความสำเร็จ / ความล้มเหลว + คุณค่า มาจากพื้นหลัง C ++ ฉันคิดว่าเขาต้องการใช้ null (แทนวัตถุ) หรือไม่เขาจะไม่ถามคำถามนี้ตั้งแต่แรก
หาว

มีความแตกต่างที่สำคัญระหว่าง "value" และ "object" การอ้างอิงค่าว่างเป็นค่าที่สะอาด แต่ไม่ใช่วัตถุ
Jon Skeet

1. ไม่มีInteger.tryParseในIntegerคลาสJava มาตรฐาน 2. การทำnew Integerไม่จำเป็น (และแนะนำให้ทำ) เนื่องจาก Java ทำการชกมวยและแกะกล่องโดยอัตโนมัติ Java ของคุณไม่ได้เป็นสนิมเพียงเล็กน้อย แต่เป็นสนิมมาก
ADTC

1

สิ่งที่เกี่ยวกับการแยก parseIntเมธอดล่ะ?

ทำได้ง่ายเพียงคัดลอกและวางเนื้อหาลงในยูทิลิตี้ใหม่ที่ส่งคืนIntegerหรือOptional<Integer>และแทนที่ด้วยการส่งคืน ดูเหมือนว่าจะไม่มีข้อยกเว้นในรหัสอ้างอิงแต่ควรตรวจสอบให้ดีกว่าแต่การตรวจสอบที่ดีขึ้น

การข้ามสิ่งที่จัดการข้อยกเว้นทั้งหมดจะช่วยประหยัดเวลาในการป้อนข้อมูลที่ไม่ถูกต้องได้ และวิธีนี้มีมาตั้งแต่ JDK 1.0 ดังนั้นจึงไม่น่าที่คุณจะต้องทำอะไรมากมายเพื่อให้เป็นปัจจุบัน


0

ฉันขอแนะนำให้คุณพิจารณาวิธีการเช่น

 IntegerUtilities.isValidInteger(String s)

ซึ่งคุณจะนำไปใช้ตามที่เห็นสมควร หากคุณต้องการให้ผลลัพธ์กลับมา - อาจเป็นเพราะคุณใช้ Integer.parseInt () อยู่แล้วคุณสามารถใช้เคล็ดลับอาร์เรย์

 IntegerUtilities.isValidInteger(String s, int[] result)

ที่คุณตั้งค่าผลลัพธ์ [0] เป็นค่าจำนวนเต็มที่พบในกระบวนการ


0

สิ่งนี้ค่อนข้างคล้ายกับโซลูชันของ Nikolay:

 private static class Box<T> {
  T me;
  public Box() {}
  public T get() { return me; }
  public void set(T fromParse) { me = fromParse; }
 }

 private interface Parser<T> {
  public void setExclusion(String regex);
  public boolean isExcluded(String s);
  public T parse(String s);
 }

 public static <T> boolean parser(Box<T> ref, Parser<T> p, String toParse) {
  if (!p.isExcluded(toParse)) {
   ref.set(p.parse(toParse));
   return true;
  } else return false;
 }

 public static void main(String args[]) {
  Box<Integer> a = new Box<Integer>();
  Parser<Integer> intParser = new Parser<Integer>() {
   String myExclusion;
   public void setExclusion(String regex) {
    myExclusion = regex;
   }
   public boolean isExcluded(String s) {
    return s.matches(myExclusion);
   }
   public Integer parse(String s) {
    return new Integer(s);
   }
  };
  intParser.setExclusion("\\D+");
  if (parser(a,intParser,"123")) System.out.println(a.get());
  if (!parser(a,intParser,"abc")) System.out.println("didn't parse "+a.get());
 }

วิธีการหลักสาธิตรหัส อีกวิธีหนึ่งในการติดตั้งอินเทอร์เฟซ Parser ก็คือการตั้งค่า "\ D +" จากโครงสร้างและไม่มีวิธีการใด


0

คุณสามารถม้วนของคุณเอง แต่มันเป็นเพียงแค่เรื่องง่ายที่จะใช้คอมมอน lang ของวิธีการStringUtils.isNumeric() ใช้Character.isDigit ()เพื่อวนซ้ำอักขระแต่ละตัวใน String


จากนั้นจะใช้ไม่ได้หากตัวเลขมีจำนวนมากเกินไป Integer.parseInt แสดงข้อยกเว้นสำหรับตัวเลขที่ใหญ่กว่า Integer.MAX_VALUE (เช่นเดียวกับด้านลบ)
Searles

0

วิธีที่ฉันจัดการกับปัญหานี้เกิดขึ้นซ้ำ ๆ ตัวอย่างเช่นเมื่ออ่านข้อมูลจากคอนโซล:

Java.util.Scanner keyboard = new Java.util.Scanner(System.in);

public int GetMyInt(){
    int ret;
    System.out.print("Give me an Int: ");
    try{
        ret = Integer.parseInt(keyboard.NextLine());

    }
    catch(Exception e){
        System.out.println("\nThere was an error try again.\n");
        ret = GetMyInt();
    }
    return ret;
}

0

เพื่อหลีกเลี่ยงข้อยกเว้นคุณสามารถใช้Format.parseObjectวิธีการของ Java โค้ดด้านล่างนี้เป็นคลาสIntegerValidatorของ Apache Common เวอร์ชันที่เรียบง่าย

public static boolean tryParse(String s, int[] result)
{
    NumberFormat format = NumberFormat.getIntegerInstance();
    ParsePosition position = new ParsePosition(0);
    Object parsedValue = format.parseObject(s, position);

    if (position.getErrorIndex() > -1)
    {
        return false;
    }

    if (position.getIndex() < s.length())
    {
        return false;
    }

    result[0] = ((Long) parsedValue).intValue();
    return true;
}

คุณสามารถใช้AtomicIntegerหรือint[]เคล็ดลับอาร์เรย์ขึ้นอยู่กับความต้องการของคุณ

นี่คือการทดสอบของฉันที่ใช้มัน -

int[] i = new int[1];
Assert.assertTrue(IntUtils.tryParse("123", i));
Assert.assertEquals(123, i[0]);

0

ฉันก็มีปัญหาเดียวกัน นี่เป็นวิธีที่ฉันเขียนขึ้นเพื่อขออินพุตจากผู้ใช้และไม่ยอมรับอินพุตเว้นแต่เป็นจำนวนเต็ม โปรดทราบว่าฉันเป็นมือใหม่ดังนั้นหากรหัสไม่ทำงานตามที่คาดไว้ก็ต้องโทษความไม่มีประสบการณ์ของฉัน!

private int numberValue(String value, boolean val) throws IOException {
    //prints the value passed by the code implementer
    System.out.println(value);
    //returns 0 is val is passed as false
    Object num = 0;
    while (val) {
        num = br.readLine();
        try {
            Integer numVal = Integer.parseInt((String) num);
            if (numVal instanceof Integer) {
                val = false;
                num = numVal;
            }
        } catch (Exception e) {
            System.out.println("Error. Please input a valid number :-");
        }
    }
    return ((Integer) num).intValue();
}

1
อย่าใช้ System.out.println (เป็นการปฏิบัติที่ไม่ดี) ปัญหาในการใช้งานคือโปรแกรมของคุณจะรอจนกว่า println จะเสร็จสิ้น แนวทางที่ดีกว่าคือการใช้กรอบการบันทึก
Omar Hrynkiewicz

0

นี่คือคำตอบสำหรับคำถาม 8391979 "java มี int.tryparse ที่ไม่ทำให้เกิดข้อยกเว้นสำหรับข้อมูลที่ไม่ถูกต้องหรือไม่ [ซ้ำ]" ซึ่งปิดและเชื่อมโยงกับคำถามนี้

แก้ไข 2016 08 17: เพิ่มวิธีการ ltrimZeroes และเรียกใช้ใน tryParse () หากไม่มีเลขศูนย์นำหน้าใน numberString อาจให้ผลลัพธ์ที่ผิดพลาด (ดูความคิดเห็นในโค้ด) ขณะนี้ยังมีวิธีการ String ltrimZeroes (String numberString) แบบคงที่สาธารณะซึ่งใช้ได้กับ "ตัวเลข" ที่เป็นบวกและลบ (END Edit)

ด้านล่างนี้คุณจะพบคลาส Wrapper พื้นฐาน (boxing) สำหรับ int ด้วยวิธีการ tryParse () ที่ปรับความเร็วสูง (คล้ายกับใน C #) ซึ่งแยกวิเคราะห์สตริงเองและเร็วกว่า Integer.parseInt (String s) เล็กน้อยจาก Java เล็กน้อย:

public class IntBoxSimple {
    // IntBoxSimple - Rudimentary class to implement a C#-like tryParse() method for int
    // A full blown IntBox class implementation can be found in my Github project
    // Copyright (c) 2016, Peter Sulzer, Fürth
    // Program is published under the GNU General Public License (GPL) Version 1 or newer

    protected int _n; // this "boxes" the int value

    // BEGIN The following statements are only executed at the
    // first instantiation of an IntBox (i. e. only once) or
    // already compiled into the code at compile time:
    public static final int MAX_INT_LEN =
            String.valueOf(Integer.MAX_VALUE).length();
    public static final int MIN_INT_LEN =
            String.valueOf(Integer.MIN_VALUE).length();
    public static final int MAX_INT_LASTDEC =
            Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(1));
    public static final int MAX_INT_FIRSTDIGIT =
            Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(0, 1));
    public static final int MIN_INT_LASTDEC =
            -Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(2));
    public static final int MIN_INT_FIRSTDIGIT =
            Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(1,2));
    // END The following statements...

    // ltrimZeroes() methods added 2016 08 16 (are required by tryParse() methods)
    public static String ltrimZeroes(String s) {
        if (s.charAt(0) == '-')
            return ltrimZeroesNegative(s);
        else
            return ltrimZeroesPositive(s);
    }
    protected static String ltrimZeroesNegative(String s) {
        int i=1;
        for ( ; s.charAt(i) == '0'; i++);
        return ("-"+s.substring(i));
    }
    protected static String ltrimZeroesPositive(String s) {
        int i=0;
        for ( ; s.charAt(i) == '0'; i++);
        return (s.substring(i));
    }

    public static boolean tryParse(String s,IntBoxSimple intBox) {
        if (intBox == null)
            // intBoxSimple=new IntBoxSimple(); // This doesn't work, as
            // intBoxSimple itself is passed by value and cannot changed
            // for the caller. I. e. "out"-arguments of C# cannot be simulated in Java.
            return false; // so we simply return false
        s=s.trim(); // leading and trailing whitespace is allowed for String s
        int len=s.length();
        int rslt=0, d, dfirst=0, i, j;
        char c=s.charAt(0);
        if (c == '-') {
            if (len > MIN_INT_LEN) { // corrected (added) 2016 08 17
                s = ltrimZeroesNegative(s);
                len = s.length();
            }
            if (len >= MIN_INT_LEN) {
                c = s.charAt(1);
                if (!Character.isDigit(c))
                    return false;
                dfirst = c-'0';
                if (len > MIN_INT_LEN || dfirst > MIN_INT_FIRSTDIGIT)
                    return false;
            }
            for (i = len - 1, j = 1; i >= 2; --i, j *= 10) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt -= (c-'0')*j;
            }
            if (len < MIN_INT_LEN) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt -= (c-'0')*j;
            } else {
                if (dfirst >= MIN_INT_FIRSTDIGIT && rslt < MIN_INT_LASTDEC)
                    return false;
                rslt -= dfirst * j;
            }
        } else {
            if (len > MAX_INT_LEN) { // corrected (added) 2016 08 16
                s = ltrimZeroesPositive(s);
                len=s.length();
            }
            if (len >= MAX_INT_LEN) {
                c = s.charAt(0);
                if (!Character.isDigit(c))
                    return false;
                dfirst = c-'0';
                if (len > MAX_INT_LEN || dfirst > MAX_INT_FIRSTDIGIT)
                    return false;
            }
            for (i = len - 1, j = 1; i >= 1; --i, j *= 10) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt += (c-'0')*j;
            }
            if (len < MAX_INT_LEN) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt += (c-'0')*j;
            }
            if (dfirst >= MAX_INT_FIRSTDIGIT && rslt > MAX_INT_LASTDEC)
                return false;
            rslt += dfirst*j;
        }
        intBox._n=rslt;
        return true;
    }

    // Get the value stored in an IntBoxSimple:
    public int get_n() {
        return _n;
    }
    public int v() { // alternative shorter version, v for "value"
        return _n;
    }
    // Make objects of IntBoxSimple (needed as constructors are not public):
    public static IntBoxSimple makeIntBoxSimple() {
        return new IntBoxSimple();
    }
    public static IntBoxSimple makeIntBoxSimple(int integerNumber) {
        return new IntBoxSimple(integerNumber);
    }

    // constructors are not public(!=:
    protected IntBoxSimple() {} {
        _n=0; // default value an IntBoxSimple holds
    }
    protected IntBoxSimple(int integerNumber) {
        _n=integerNumber;
    }
}

โปรแกรมทดสอบ / ตัวอย่างสำหรับคลาส IntBoxSimple:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class IntBoxSimpleTest {
    public static void main (String args[]) {
        IntBoxSimple ibs = IntBoxSimple.makeIntBoxSimple();
        String in = null;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        do {
            System.out.printf(
                    "Enter an integer number in the range %d to %d:%n",
                        Integer.MIN_VALUE, Integer.MAX_VALUE);
            try { in = br.readLine(); } catch (IOException ex) {}
        } while(! IntBoxSimple.tryParse(in, ibs));
        System.out.printf("The number you have entered was: %d%n", ibs.v());
    }
}

0

ลองใช้นิพจน์ทั่วไปและอาร์กิวเมนต์พารามิเตอร์เริ่มต้น

public static int parseIntWithDefault(String str, int defaultInt) {
    return str.matches("-?\\d+") ? Integer.parseInt(str) : defaultInt;
}


int testId = parseIntWithDefault("1001", 0);
System.out.print(testId); // 1001

int testId = parseIntWithDefault("test1001", 0);
System.out.print(testId); // 1001

int testId = parseIntWithDefault("-1001", 0);
System.out.print(testId); // -1001

int testId = parseIntWithDefault("test", 0);
System.out.print(testId); // 0

หากคุณใช้ apache.commons.lang3 ให้ใช้NumberUtils :

int testId = NumberUtils.toInt("test", 0);
System.out.print(testId); // 0

0

ฉันต้องการส่งข้อเสนออื่นที่ใช้ได้ผลหากมีการร้องขอโดยเฉพาะจำนวนเต็ม: ใช้แบบยาวและใช้ Long.MIN_VALUE สำหรับกรณีข้อผิดพลาด สิ่งนี้คล้ายกับวิธีการที่ใช้สำหรับตัวอักษรใน Reader โดยที่ Reader.read () จะส่งคืนจำนวนเต็มในช่วงของ char หรือ -1 หากผู้อ่านว่างเปล่า

สำหรับ Float และ Double สามารถใช้ NaN ในลักษณะเดียวกันได้

public static long parseInteger(String s) {
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException e) {
        return Long.MIN_VALUE;
    }
}


// ...
long l = parseInteger("ABC");
if (l == Long.MIN_VALUE) {
    // ... error
} else {
    int i = (int) l;
}

0

เมื่อพิจารณาถึงคำตอบที่มีอยู่ฉันได้คัดลอกวางและปรับปรุงซอร์สโค้ดInteger.parseIntเพื่อทำงานนี้และวิธีแก้ปัญหาของฉัน

  • ไม่ใช้ try-catch ที่อาจช้า (ไม่เหมือนLang 3 NumberUtils )
  • ไม่ใช้ regexps ที่ไม่สามารถจับตัวเลขที่ใหญ่เกินไป
  • หลีกเลี่ยงการชกมวย (ไม่เหมือนของฝรั่งInts.tryParse())
  • ไม่จำเป็นต้องมีการจัดสรรใด ๆ (ไม่เหมือนint[], Box,OptionalInt )
  • ยอมรับส่วนใดCharSequenceส่วนหนึ่งหรือบางส่วนแทนทั้งหมดString ,
  • สามารถใช้ radix ใดก็ได้ Integer.parseIntสามารถเช่น [2,36]
  • ไม่ขึ้นอยู่กับไลบรารีใด ๆ

ข้อเสียเพียงอย่างเดียวคือว่าไม่มีความแตกต่างระหว่างและtoIntOfDefault("-1", -1)toIntOrDefault("oops", -1)

public static int toIntOrDefault(CharSequence s, int def) {
    return toIntOrDefault0(s, 0, s.length(), 10, def);
}
public static int toIntOrDefault(CharSequence s, int def, int radix) {
    radixCheck(radix);
    return toIntOrDefault0(s, 0, s.length(), radix, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int def) {
    boundsCheck(start, endExclusive, s.length());
    return toIntOrDefault0(s, start, endExclusive, 10, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int radix, int def) {
    radixCheck(radix);
    boundsCheck(start, endExclusive, s.length());
    return toIntOrDefault0(s, start, endExclusive, radix, def);
}
private static int toIntOrDefault0(CharSequence s, int start, int endExclusive, int radix, int def) {
    if (start == endExclusive) return def; // empty

    boolean negative = false;
    int limit = -Integer.MAX_VALUE;

    char firstChar = s.charAt(start);
    if (firstChar < '0') { // Possible leading "+" or "-"
        if (firstChar == '-') {
            negative = true;
            limit = Integer.MIN_VALUE;
        } else if (firstChar != '+') {
            return def;
        }

        start++;
        // Cannot have lone "+" or "-"
        if (start == endExclusive) return def;
    }
    int multmin = limit / radix;
    int result = 0;
    while (start < endExclusive) {
        // Accumulating negatively avoids surprises near MAX_VALUE
        int digit = Character.digit(s.charAt(start++), radix);
        if (digit < 0 || result < multmin) return def;
        result *= radix;
        if (result < limit + digit) return def;
        result -= digit;
    }
    return negative ? result : -result;
}
private static void radixCheck(int radix) {
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        throw new NumberFormatException(
                "radix=" + radix + " ∉ [" +  Character.MIN_RADIX + "," + Character.MAX_RADIX + "]");
}
private static void boundsCheck(int start, int endExclusive, int len) {
    if (start < 0 || start > len || start > endExclusive)
        throw new IndexOutOfBoundsException("start=" + start + " ∉ [0, min(" + len + ", " + endExclusive + ")]");
    if (endExclusive > len)
        throw new IndexOutOfBoundsException("endExclusive=" + endExclusive + " > s.length=" + len);
}

0

อาจมีใครบางคนกำลังมองหาวิธีการทั่วไปมากกว่านี้เนื่องจาก Java 8 มีแพ็คเกจjava.util.functionที่อนุญาตให้กำหนดฟังก์ชันซัพพลายเออร์ คุณสามารถมีฟังก์ชันที่รับซัพพลายเออร์และค่าเริ่มต้นได้ดังนี้:

public static <T> T tryGetOrDefault(Supplier<T> supplier, T defaultValue) {
    try {
        return supplier.get();
    } catch (Exception e) {
        return defaultValue;
    }
}

ด้วยฟังก์ชั่นนี้คุณสามารถเรียกใช้วิธีการแยกวิเคราะห์ใด ๆ หรือแม้แต่วิธีการอื่น ๆ ที่อาจทำให้เกิดข้อยกเว้นในขณะที่มั่นใจได้ว่าจะไม่มีข้อยกเว้นใด ๆ เกิดขึ้นได้:

Integer i = tryGetOrDefault(() -> Integer.parseInt(stringValue), 0);
Long l = tryGetOrDefault(() -> Long.parseLong(stringValue), 0l);
Double d = tryGetOrDefault(() -> Double.parseDouble(stringValue), 0d);

-1

คุณสามารถใช้ Null-Object ได้ดังนี้:

public class Convert {

    @SuppressWarnings({"UnnecessaryBoxing"})
    public static final Integer NULL = new Integer(0);

    public static Integer convert(String integer) {

        try {
            return Integer.valueOf(integer);
        } catch (NumberFormatException e) {
            return NULL;
        }

    }

    public static void main(String[] args) {

        Integer a = convert("123");
        System.out.println("a.equals(123) = " + a.equals(123));
        System.out.println("a == NULL " + (a == NULL));

        Integer b = convert("onetwothree");
        System.out.println("b.equals(123) = " + b.equals(123));
        System.out.println("b == NULL " + (b == NULL));

        Integer c = convert("0");
        System.out.println("equals(0) = " + c.equals(0));
        System.out.println("c == NULL " + (c == NULL));

    }

}

ผลลัพธ์ของmainในตัวอย่างนี้คือ:

a.equals(123) = true
a == NULL false
b.equals(123) = false
b == NULL true
c.equals(0) = true
c == NULL false

ด้วยวิธีนี้คุณสามารถทดสอบการแปลงที่ล้มเหลวได้ตลอดเวลา แต่ยังคงใช้ผลลัพธ์เป็นอินสแตนซ์จำนวนเต็ม คุณอาจต้องการปรับแต่งตัวเลขNULLแทน (≠ 0)


จะเกิดอะไรขึ้นถ้า 'String integer' เป็น String literal "0"? คุณจะไม่มีทางรู้ว่ามีข้อมูลที่ไม่ถูกต้องหรือไม่
Bart Kiers

ฉันเดาว่าขึ้นอยู่กับว่าตัวดำเนินการ == สำหรับจำนวนเต็มสองตัวเปรียบเทียบค่าหรือการอ้างอิง หากเปรียบเทียบค่าแสดงว่ามีปัญหาอยู่ หากเปรียบเทียบการอ้างอิงก็จะทำงานได้เทียบเท่ากับคำตอบของฉัน
Adam Maras

ทำไมต้องโหวตลง? คำตอบของฉันถูกต้องและมีข้อได้เปรียบ (เกินค่าว่าง) ที่คุณจัดการกับอินสแตนซ์ที่ถูกต้องของจำนวนเต็ม (แทนที่จะเป็นค่าว่าง) ช่วยให้คุณไม่ต้องจัดการกับ NPE
หาว

แตกต่างจาก null จำนวนเต็มจริงเป็นประโยชน์แม้ว่า คุณควรทดสอบผลลัพธ์เพื่อหาค่าว่างเพื่อให้ทราบว่าการแยกวิเคราะห์สำเร็จหรือไม่ การซ่อนวัตถุที่อยู่เบื้องหลังและใช้งานได้เป็นสูตรสำหรับปัญหา IMO
Jon Skeet

downvotes เพิ่มเติม - น่าสนใจ! เนื่องจาก / ฉันยังใหม่กับ SO และผู้มีสิทธิเลือกตั้งคนใดคนหนึ่งสามารถอธิบายให้ฉันฟังว่าทำไม?
หาว

-1

คุณไม่ควรใช้ข้อยกเว้นเพื่อตรวจสอบค่าของคุณคุณไม่ควรใช้ข้อยกเว้นในการตรวจสอบค่าของคุณ

สำหรับอักขระเดี่ยวมีวิธีง่ายๆดังนี้

Character.isDigit()

สำหรับค่าที่ยาวขึ้นควรใช้ยูทิลิตี้บางอย่าง NumberUtils จาก Apache จะทำงานได้อย่างสมบูรณ์แบบที่นี่:

NumberUtils.isNumber()

โปรดตรวจสอบhttps://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html


«ตรวจสอบว่าสตริงเป็นหมายเลข Java ที่ถูกต้องหรือไม่ ตัวเลขที่ถูกต้อง ได้แก่ เลขฐานสิบหกที่ทำเครื่องหมายด้วยคุณสมบัติ 0x สัญกรณ์ทางวิทยาศาสตร์และตัวเลขที่มีเครื่องหมายระบุประเภท (เช่น 123L) » นี่ไม่ใช่สิ่งที่สามารถแยกวิเคราะห์Integer.parseIntได้
Miha_x64
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.