2011-02-08 37 views
18

tôi chỉ tìm thấy một lỗi trong một số mã tôi đã không viết và tôi là một chút ngạc nhiên:Mẫu "tĩnh" không nên tĩnh?

Pattern pattern = Pattern.compile("\\d{1,2}.\\d{1,2}.\\d{4}"); 
Matcher matcher = pattern.matcher(s); 

Mặc dù thực tế rằng mã này thất bại nặng nề trên dữ liệu đầu vào chúng tôi nhận (vì nó cố gắng tìm ngày theo định dạng 2011/01/17 và được trở lại những thứ như 10396/2011 và sau đó bị rơi vì nó không thể phân tích cú pháp ngày nhưng điều đó thực sự không phải là điểm của câu hỏi này;) tôi tự hỏi:

  • không phải là một trong các điểm của Pa ttern.compile là một tối ưu hóa tốc độ (bằng cách biên dịch trước khi biên dịch)?

  • không phải tất cả mẫu "tĩnh" là luôn là được biên dịch thành mẫu tĩnh?

Có rất nhiều ví dụ, tất cả khắp nơi trên web, nơi mà cùng một khuôn mẫu luôn được biên dịch lại bằng Pattern.compile mà tôi bắt đầu tự hỏi, nếu tôi nhìn thấy mọi thứ hay không.

Không phải là (giả định rằng chuỗi là tĩnh và do đó không động xây dựng):

static Pattern pattern = Pattern.compile("\\d{1,2}.\\d{1,2}.\\d{4}"); 

luôn preferrable trên một tài liệu tham khảo mẫu không tĩnh?

+4

Lỗi trong mẫu là '.' khớp với bất kỳ thứ gì. Sử dụng '\ .' (hoặc đúng hơn' \\. '; Dấu gạch chéo ngược đầu tiên là dành cho Java) để sửa lỗi đó. –

+0

@Donal Fellows: cảm ơn rất nhiều, tôi biết tôi biết, tôi chỉ muốn dán mã bị hỏng khi tôi đọc nó. Đối với tôi có ** hai ** WTF trong mã này: đầu tiên là việc biên dịch mẫu không phải là tĩnh và sau đó thứ hai là vấn đề tổng thể * regexp-now-you-have-two-problems * :) – Gugussee

+1

Tất cả các câu trả lời nói rằng biên dịch tĩnh là tốt hơn là chính xác. Nhưng có một chút tối ưu hóa sớm ở đây. Nếu bạn thấy nhiều ví dụ trên web bằng cách sử dụng Pattern.compile không tĩnh, có thể vì nó đơn giản không phải là nút cổ chai thường xuyên, và có thể chỉ là một chút nhỏ để đọc hoặc duy trì theo cách đó. Luôn luôn đo lường trước khi tối ưu hóa, nếu không bạn có thể thấy rằng thời gian dành riêng cho việc khám phá vấn đề lớn hơn tất cả thời gian CPU mà chương trình của bạn sẽ chi tiêu trong Pattern.compile kết hợp với nhau :-). – Avi

Trả lời

23
  1. Có, toàn bộ điểm biên dịch trước là Pattern chỉ thực hiện một lần.
  2. Nó thực sự phụ thuộc vào cách bạn sẽ sử dụng nó, nhưng nói chung, các mẫu được biên dịch trước được lưu trữ trong các trường static sẽ ổn. (Không giống như Matcher s, không an toàn cho chủ đề và do đó không thực sự được lưu trữ trong các trường ở tất cả, tĩnh hay không.)

Thông báo duy nhất với các mẫu biên dịch trong bộ khởi tạo tĩnh là nếu mẫu đó không ' t biên dịch và khởi tạo tĩnh ném một ngoại lệ, nguồn gốc của lỗi có thể khá khó chịu để theo dõi. Đó là một vấn đề bảo trì nhỏ nhưng nó có thể đáng nói đến.

+0

sử dụng một IDE tốt chắc chắn sẽ giúp ở đây. .. IntelliJ IDEA sẽ chỉ rõ các lỗi trong mẫu không biên dịch (ngay cả trên mã nguồn không đầy đủ). – SyntaxT3rr0r

+0

@ SyntaxT3rr0r Đó là một tính năng khá thú vị. (Nhân tiện, tôi đã không quên câu hỏi đại lý-GC của bạn, tôi vừa mới nhận ra mình đã quên cách viết mã trong C, vì vậy phải mất nhiều thời gian hơn để tìm ra giải pháp làm việc.) – biziclop

+0

http: // stackoverflow.com/questions/1360113/is-java-regex-thread-safe –

11

trước tiên, lỗi trong mẫu là do dấu chấm (.) Khớp với mọi thứ. (.) Nếu bạn muốn kết hợp chấm bạn phải thoát khỏi nó trong regex:

Pattern pattern = Pattern.compile("\\d{1,2}\\.\\d{1,2}\\.\\d{4}");

Thứ hai, Pattern.compile() là một phương pháp nặng. Nó luôn luôn được khuyến khích để khởi tạo mô hình tĩnh (tôi có nghĩa là các mẫu không được thay đổi hoặc không được tạo ra trên bay) chỉ một lần. Một trong những cách phổ biến để đạt được điều này là đặt Pattern.compile() vào bộ khởi tạo tĩnh.

Bạn có thể sử dụng cách tiếp cận khác. Ví dụ sử dụng mẫu đơn hoặc sử dụng khung làm việc tạo ra các đối tượng đơn lẻ (như Spring).

+0

Tôi biết rằng đó là vì dấu chấm phù hợp với mọi thứ;) Tôi nghĩ tôi sẽ đi với tĩnh initializer trong trường hợp này: sử dụng mẫu Singleton của Spring để tạo một thể hiện của một Pattern có vẻ hơi cực đoan :) – Gugussee

+0

Chắc chắn, tôi không đề nghị bạn sử dụng Spring chỉ để tạo ra thể hiện của mẫu. Tôi chỉ nói rằng có những giải pháp khác với khởi tạo tĩnh. Tôi có nghĩa là nếu bạn đã sử dụng mùa xuân trong dự án của bạn, bạn có thể đặt tất cả các mẫu cho một hạt đơn và lấy chúng khi bạn cần. – AlexR

+3

@AlexR Làm thế nào để instantiating 'Pattern' trong một initializer tĩnh như' static {} 'khác với việc khai báo' Pattern' như một trường tĩnh như 'private static final Pattern pattern = Pattern.compile()'? –

3

Có, việc biên dịch Mẫu trên mỗi lần sử dụng là lãng phí và xác định mẫu tĩnh sẽ dẫn đến hiệu suất tốt hơn. Xem this SO thread để có cuộc thảo luận tương tự.

+0

cảm ơn vì liên kết – Gugussee

0

Mẫu tĩnh sẽ vẫn còn trong bộ nhớ miễn là lớp được tải.

Nếu bạn lo lắng về bộ nhớ và muốn dùng một lần ném Pattern mà bạn sử dụng một lần trong một thời gian và có thể thu gom rác khi bạn đã hoàn thành nó, thì bạn có thể sử dụng số Pattern không tĩnh.

0

Đây là thời điểm cổ điển so với giao dịch bộ nhớ. Nếu bạn chỉ biên dịch Mẫu một lần, đừng dán nó vào trường tĩnh. Nếu bạn đo các mẫu biên dịch chậm, biên dịch trước và đặt nó vào một trường tĩnh.

Các vấn đề liên quan