2012-02-26 31 views
13

Vì vậy, tôi thấy bản thân mình đang làm một việc gì đó giống như mô hình sau đây. Thay vì:mẫu java: khi nào có ý nghĩa khi sử dụng các biến tạm thời

if (map.containsKey(someKey)) { 
    Value someValue = map.get(someKey); 
    ... 
} 

Để không đi qua bản đồ hai lần (và kể từ khi tôi biết bản đồ của tôi không lưu trữ null), tôi sẽ thực hiện:

Value someValue = map.get(someKey); 
if (someValue != null) { 
    ... 
} 

Điều này dường như tôi trở thành một giá trị mô hình cho rằng các hoạt động Map thực hiện một số lượng phong nha của các hoạt động và tối ưu hóa, tôi giả định, không đủ thông minh để tối ưu hóa nó đi.

Nhưng sau đó tôi thấy mình đang làm các mẫu tương tự trong các tình huống khác. Ví dụ: tôi có nên lưu trữ kết quả someMethod() trong biến tạm thời thay vì thực hiện cuộc gọi hai lần không? Rõ ràng tôi không thể gọi số someMethod() hai lần nếu có phản ứng phụ nhưng khi nào nó có ý nghĩa khi chỉ gọi nó một lần từ quan điểm tối ưu hóa?

if (someObject.someMethod() != null) { 
    processSomehow(someObject.someMethod()); 
} 

Tôi biết biên giới này về câu hỏi "không mang tính xây dựng" nên tôi đang tìm câu trả lời trình bày một số thông tin và tham khảo thay vì phỏng đoán.

  • Khi nào có ý nghĩa khi thực hiện việc này và khi nào?
  • Làm cách nào để đánh giá "chi phí" của someMethod() để xác định thời điểm sử dụng biến tạm thời?
  • Đối với các phương pháp đơn giản như nhận các phương pháp, điều này có thể cản trở trình biên dịch hotspot hoặc trình tối ưu hóa và thực sự tạo ra mã ít hiệu quả hơn không?

Vì hậu thế, tôi không hỏi "làm cách nào tôi có thể cải thiện tốc độ của chương trình hiện tại". Tôi đang cố gắng tìm ra "Tôi nên sử dụng mẫu nào khi viết mã trong tương lai".

Cảm ơn mọi thông tin.

+6

Tôi nghĩ câu trả lời cho tất cả các câu hỏi này liên quan đến từ "profiler" ... –

+4

Rõ ràng nếu 'someMethod()' là tốn kém hoặc có tác dụng phụ bạn không muốn gọi nó hai lần. Java không (chưa) chứa một từ khóa 'idempotent' (mang lại những ký ức cũ về' reducible' trong PL/1 :-) –

+0

Điểm tốt @Jim. Tôi đã chỉnh sửa câu hỏi của mình để làm rõ hơn rằng tôi không nói về tác dụng phụ. Nhưng những gì tôi đang nói đến là làm thế nào để đánh giá "chi phí" của phương pháp. – Gray

Trả lời

11

Làm cách nào để đánh giá "chi phí" của someMethod() để xác định thời điểm sử dụng biến tạm thời?

Chỉ cần xem xét việc triển khai someMethod(). Nếu nó chỉ trả về một trường - giống như một phương thức getter thông thường sẽ làm, không cần khai báo biến cục bộ (hiệu năng khôn ngoan). Nếu phương thức tạo đối tượng, gọi cơ sở dữ liệu hoặc đọc nội dung tệp, thì thường là khôn ngoan để lưu trữ giá trị trả về.

Cá nhân, tôi không quan tâm đến các vấn đề về hiệu suất gây ra tuyên bố biến tạm thời. Tôi chỉ giữ giá trị trả về thay vì gọi phương thức hai lần. Mã dễ đọc và dễ hiểu hơn nhiều (trừ khi bạn đặt tên cho tất cả các biến đó chỉ temp ;-))

+0

Vài chi tiết cụ thể (cơ sở dữ liệu, đối tượng mới) có @Andreas nhưng bạn có thể cung cấp thêm một số chi tiết về cách bạn đánh giá chi phí của một phương thức hay không. Nó không đơn giản như "nhìn" ing vào nó. – Gray

+2

Ngưỡng của tôi khá thấp. Tất cả mọi thứ đắt tiền hơn sau đó 'trở lại mValue;' sẽ được lưu trữ;) - btw, tôi tin rằng, chúng tôi có thể ước tính sự phức tạp/chi phí bằng cách chỉ nhìn vào mã. –

+0

Tôi đã cố gắng để biết thêm chi tiết. "Tất cả mọi thứ đắt tiền hơn sau đó trả lại mValue;" là những gì tôi đang tìm kiếm. Cảm ơn. – Gray

5

Rõ ràng tôi không thể gọi someMethod() hai lần nếu có tác dụng phụ nhưng khi nào nó thực hiện cảm giác chỉ gọi nó một lần từ quan điểm tối ưu hóa?

Khi bạn đã chứng minh rằng nó quan trọng bằng cách sử dụng trình thu thập thông tin. Nhưng có được sử dụng để không gọi phương pháp hai lần liên tiếp anyway, vì nó sẽ làm cho bảo trì dễ dàng hơn (nếu kiểm tra thay đổi và bạn quên thay đổi nó ở cả hai nơi?). Sử dụng các biến tạm thời một cách tự do, chúng cực kỳ rẻ.

+2

Tôi nghĩ rằng "tự do" có thể cần phải đủ điều kiện. Phát hiện ra các phương pháp của bạn với các biến sử dụng một lần cũng có những nhược điểm của nó. –

+1

Thực ra, tôi có xu hướng giới thiệu mỗi khi tôi cần thực hiện một thao tác hai lần mà không có biến. –

+0

Tôi không có thời gian để hồ sơ ứng dụng của mình mỗi lần tôi cần đánh giá xem có cần biến tạm thời hay không. Có bất kỳ mẫu nào bạn tìm kiếm @larsmans trong khi bạn đang mã hóa không? – Gray

5

Theo nguyên tắc chung, tôi sử dụng biến cục bộ khi tôi cần nhiều hơn một lần. Bạn có thể cho rằng địa phương var một tên khá và tất cả mọi người biết những gì var này là về. Từ quan điểm thực hiện: Các vars cục bộ rẻ và các phương pháp có thể phức tạp.

Đặc biệt khi someMethod() đắt tiền như phương thức được đồng bộ hóa thì điều này sẽ hoạt động tốt hơn nhiều. Nhưng khi someMethod() là một phương pháp đồng bộ thì nó được dự định để được gọi bởi nhiều chủ đề trong đồng thời và sau đó nó tạo sự khác biệt để gọi phương thức hai lần hoặc lưu trữ giá trị trả về của nó và sử dụng lại ...

... đề cập đến là các cuộc gọi phương thức tiếp theo không phải trả lại cùng một dữ liệu. Vì vậy, các ví dụ của bạn có/không có var cục bộ không phải lúc nào cũng thay thế hợp lệ cho các cuộc gọi phương thức tiếp theo. Nhưng tôi nghĩ bạn đã cân nhắc điều này rồi.

+0

Tôi chưa bao giờ nhận xét về điều này nhưng cảm ơn câu trả lời của bạn. Tôi đã cho nó một +1. Điểm tốt. – Gray

1

Nhắc tôi về một cuộc thảo luận về tương tự NET Dictionary sử dụng phong cách: What is more efficient: Dictionary TryGetValue or ContainsKey+Item?

Nói chung, như đã chỉ ra trong các ý kiến, bạn không biết những điểm nóng thực hiện trong chương trình của bạn cho đến khi bạn chạy nó với dữ liệu thực dưới một hồ sơ.

Ngoài ra, nói chung, trình biên dịch trong ngôn ngữ mệnh lệnh không thể tối ưu hóa các cuộc gọi lặp lại, vì các tác dụng phụ có thể xảy ra. Mọi cuộc gọi đến một hàm đều có thể trả về một giá trị mới. Và bằng cách này, đó cũng là một trong những lý do tại sao bản thân bạn không nên dựa vào các cuộc gọi lặp đi lặp lại. Hôm nay có thể bạn biết rằng một hàm hoặc thuộc tính là các tác dụng phụ miễn phí và lặp lại các cuộc gọi trả về cùng một giá trị, nhưng ngày mai bạn thay đổi nó và thêm một số trình tạo ngẫu nhiên bên trong và tất cả logic với các cuộc gọi lặp lại sẽ bị hỏng.

2

Đối với tôi, tất cả điều này sẽ làm giảm hiệu suất của chương trình và không hoạt động. Vì vậy,

if (map.containsKey(someKey)) { 
    Value someValue = map.get(someKey); 
    ... 
} 

không tương đương với mã mà trong mọi trường hợp:

Value someValue = map.get(someKey); 
if (someValue != null) { 
    ... 
} 

Hãy xem xét một bản đồ, nơi giá trị thể được null cho một chìa khóa nhất định. Nếu phần ...null an toàn thì mã hoạt động khác nhau.

Ngoài ra mã này bằng cách nào đó có vấn đề logic. Xem xét việc này:

BufferedRead reader = ...; 
if (reader.readLine() != null) { 
    processSomehow(reader.readLine()); 
} 

Đây rõ ràng là readLinephải được gọi là hai lần. Một vấn đề tên miền cho loại mã này là đa luồng: Mã dự kiến ​​giá trị không thay đổi, nhưng một chủ đề khác có thể làm excatly này.

Tóm tắt Giữ mã của bạn rõ ràng và chính xác nhất có thể. Điều này có nghĩa, nếu bạn mong đợi một giá trị không thay đổi và bạn cần nó nhiều lần, thì hãy sử dụng biến số cho bất kỳ ai biết điều này.

+0

Tôi đã không nói về logic @ A.H .. Tôi hiểu khi tôi _need_ sử dụng các biến tạm thời. Tôi đã cố gắng để tìm ra khi nó được khuyến khích. – Gray

+0

@Gray: Tôi hiểu rõ quan điểm của bạn. Quan điểm của tôi là: Logic đến trước.Khi logic ra lệnh, cùng một giá trị được mong đợi, thì các biến phải được sử dụng. Do đó, cả hai ví dụ của bạn đều sai hoặc không rõ ràng. Vì vậy: _not_ sử dụng các biến là ngoại lệ thực sự. –

+0

Mã của tôi không phải là sai trái về mặt logic và cũng không rõ ràng. Tôi biết rằng 'Bản đồ' của tôi hoặc không chấp nhận null hoặc tôi không bao giờ lưu trữ chúng ở đó. Không ai khác cần phải làm rõ điều đó. Bạn trả lời đã bỏ lỡ điểm của câu hỏi của tôi hoàn toàn. – Gray

2

Một số người đang trích dẫn Knuth (hoặc ngầm hoặc rõ ràng), nhưng tôi nghĩ điều này luôn có ý nghĩa như một mẫu thiết kế (và trường hợp null là chìa khóa cho phép, as pointed out by A.H. trở nên rõ ràng hơn nhiều). Trong tâm trí của tôi, nó tương tự như trường hợp chuyển một biến bằng tham chiếu const trong C++ thay vì theo giá trị.Có hai lý do để làm điều này: (a) nó giao tiếp rằng giá trị sẽ không thay đổi, nhưng lý do chính nó được thực hiện là nó nhanh hơn một chút. Nó không quan trọng trên hầu hết các cuộc gọi cá nhân, nhưng khi mọi thói quen vượt qua mọi thông số theo giá trị, bạn nhận thấy nó. Đó là một thói quen tốt để tham gia. Trường hợp bạn đề cập không phổ biến và vì vậy nó không quan trọng, nhưng tôi cho rằng đó vẫn là thói quen tốt.

+0

Cảm ơn. Điểm tốt. – Gray

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