2015-01-19 24 views
8

tức là, bằng cách chuyển điều kiện lỗi và không dừng toàn bộ Chế độ có thể quan sát?Rx Observable có thể xử lý ngoại lệ một cách duyên dáng trong một toán tử và tiếp tục không?

Quan sát của tôi bắt đầu bằng danh sách số theo dõi gói do người dùng cung cấp từ các dịch vụ chuyển phát thường (FedEx, UPS, DHL, v.v.), tra cứu ngày giao hàng dự kiến ​​trực tuyến, sau đó trả về ngày đó theo số ngày từ hôm nay (nghĩa là "trong 3 ngày" thay vì "ngày 22 tháng 1"). Vấn đề là nếu bất kỳ tra cứu cá nhân nào dẫn đến một ngoại lệ, toàn bộ luồng sẽ dừng và phần còn lại của các mã sẽ không được tra cứu. Không có khả năng xử lý một cách duyên dáng, ví dụ: UnknownTrackingCode Exception và vì vậy Đài quan sát không thể đảm bảo rằng nó sẽ tra cứu tất cả các mã mà người dùng đã gửi.

public void getDaysTillDelivery(List<String> tracking_code_list) { 
     Observable o = Observable.from(tracking_code_list) 
        // LookupDeliveryDate performs network calls to UPS, FedEx, USPS web sites or APIs 
        // it might throw: UnknownTrackingCode Exception, NoResponse Exception, LostPackage Exception 
       .map(tracking_code -> LookupDeliveryDate(tracking_code)) 
       .map(delivery_date -> CalculateDaysFromToday(delivery_date)); 
     o.subscribe(mySubscriber); // will handle onNext, onError, onComplete 
} 

Ngăn chặn dòng Quan sát là kết quả của một lỗi là do thiết kế:

Hành vi mặc định có thể được khắc phục , nhưng chỉ bằng cách loại bỏ rất nhiều các lợi ích của Rx ở nơi đầu tiên:

  • tôi có thể quấn LookupDeliveryDate để nó trả về Ngày thay Exceptions (như 1899-12-31 cho UnknownTrackingCode Exception) nhưng điều này ngăn cản "mã lỏng lẻo", bởi vì CalculateDaysFromToday sẽ cần phải xử lý những trường hợp đặc biệt
  • tôi có thể bao quanh mỗi chức năng ẩn danh với try/catch và khối, nhưng điều này chủ yếu ngăn cản tôi từ việc sử dụng lambdas
  • tôi có thể sử dụng if/thens chỉ đạo con đường mã, nhưng điều này sẽ có khả năng đòi hỏi phải duy trì một số nhà nước và loại bỏ đánh giá xác định
  • Lỗi xử lý từng bước, rõ ràng, ngăn củng cố tất cả các lỗi xử lý trong Subscriber
  • Viết điều hành lỗi xử lý riêng của tôi là có thể, nhưng mỏng ghi

Có cách nào tốt hơn để xử lý này?

Trả lời

4

Chính xác bạn muốn điều gì xảy ra nếu có lỗi? Bạn chỉ muốn ném mục đó đi hay bạn muốn thứ gì đó hạ lưu để làm điều gì đó với nó?

Nếu bạn muốn thứ gì đó hạ lưu để thực hiện một số hành động, thì bạn thực sự chuyển lỗi thành dữ liệu (ví dụ như ví dụ về trả về giá trị được gửi là 1899-12-31 để trình bày lỗi). Chiến lược này theo định nghĩa có nghĩa là mọi thứ ở hạ lưu cần phải hiểu rằng luồng dữ liệu có thể chứa lỗi thay vì dữ liệu và chúng phải được sửa đổi để xử lý nó.

Nhưng thay vì tạo ra giá trị phép thuật, bạn có thể biến luồng Observable của mình thành luồng giá trị Either. Giá trị là ngày hoặc đó là lỗi. Mọi thứ ở hạ lưu nhận đối tượng Either này và có thể hỏi nó nếu nó có giá trị hoặc lỗi.Nếu nó có giá trị, chúng có thể tạo ra đối tượng Either mới với kết quả tính toán của chúng. Nếu nó có lỗi và họ không thể làm bất cứ điều gì với nó, họ có thể mang lại một lỗi Hoặc là chính họ.

Tôi không biết cú pháp Java, nhưng đây là những gì nó có thể trông giống như trong C#:

Observable.From(tracking_code_list) 
    .Select(t => 
     { 
      try { return Either.From(LookupDeliveryDate(t)); } 
      catch (Exception e) 
      { 
       return Either.FromError<Date>(e); 
      } 
     }) 
    .Select(dateEither => 
     { 
      return dateEither.HasValue ? 
       Either.From(CalculateDaysFromToday(dateEither.Value)) : 
       Either.FromError<int>(dateEither.Error); 
     }) 
    .Subscribe(value => 
     { 
      if (value.HasValue) mySubscriber.OnValue(value.Value); 
      else mySubscribe.OnError(value.Error); 
     }); 

tùy chọn khác của bạn là "xử lý"/ngăn chặn các lỗi khi nó xảy ra. Điều này có thể đủ tùy thuộc vào nhu cầu của bạn. Trong trường hợp này, chỉ cần có LookupDeliveryDate ngày ma thuật trả về thay vì ngoại lệ và sau đó thêm .filter để lọc ra các ngày kỳ diệu trước khi chúng đến được CalculateDaysFromToay.

+0

_Bạn muốn chính xác điều gì xảy ra nếu có lỗi? _ Lý tưởng nhất, một cái gì đó như 'onItemError()' trong Thuê bao có thể được viết để bao gồm các loại ngoại lệ có thể biết được trên cơ sở từng mục, trong khi Người quan sát tiếp tục xử lý luồng. Kể từ khi đăng bài, tôi đã đọc nhiều hơn và điều này có thể được mô phỏng bằng 'flatMap''ing mỗi chuỗi mã theo dõi thành một mục' Quan sát ', do đó, bây giờ' onError' hoặc 'onComplete' được gọi cho mọi mục. Hack-ish, nhưng có thể làm việc. – ExactaBox

+0

Tôi đánh giá cao đề xuất của bạn và muốn giải quyết chúng: Sửa đổi các hành động hạ lưu - có thể hoạt động nhưng vi phạm khái niệm "lỏng lẻo" và các chức năng hành động không phải lúc nào cũng được thay đổi. Lọc ra các lỗi - có thể trong các luồng công việc nhất định, nhưng không thể chấp nhận được khi một phản hồi được mong đợi cho mọi đầu vào. Đối tượng 'Cả hai '- không phải là bản địa của Java 7 (Android), và bạn mất các lambdas một dòng, nhưng về mặt khái niệm thì nó có vẻ ít hack-ish và nhẹ hơn việc chuyển đổi một chuỗi' Chuỗi' thành một dòng 'Observable ' , mỗi yêu cầu phải có một đăng ký duy nhất. Cảm ơn bạn! – ExactaBox

+0

Có Hoặc không tồn tại trong C#. Bạn sẽ cần phải cuộn phiên bản của riêng bạn về khái niệm lớp học đó. – Brandon

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