2012-11-29 25 views
8

Tôi biết trong Scala một phương pháp không bao giờ nên trả lại null ... nhưng những gì về các tham số đầu vào? Với đoạn mã sau đây ...Làm thế nào để xử lý các thông số đầu vào null trong Scala

object MyObject { 

    def myMethod(p: String): Option[String] = { 
     if (p == null) throw new IllegalArgumentException("p is null.") 
     ... 
    } 
} 

... là cách tôi kiểm tra p chính xác? Có đề nghị nào không?

Trả lời

19

Quy ước là mã Scala không sử dụng null (với một số lượng nhỏ các trường hợp ngoại lệ, nên ngay lập tức được sửa khi sử dụng các chức năng thư viện đó).

Do đó, một số không từ Scala là dấu hiệu cho thấy có điều gì đó sai (ít nhất là PBCAK), vì vậy bạn cũng có thể ném một ngoại lệ. Đây không phải là hoạt động thường xuyên; đây là một cái gì đó nghiêm túc hơi say lên. Nắm bắt ngoại lệ bất cứ nơi nào bạn bắt gặp những trục trặc nghiêm trọng. Bắt một số IllegalArgumentException thay vì NullPointerException không thêm thông tin nào. Chỉ cần rời khỏi bản gốc một mình.

Nếu mã đến từ Java, cách kinh điển để xử lý nó là bọc nó trong Option, sẽ chuyển đổi null thành None. Sau đó, bạn có thể thậm chí không cần phải ném một ngoại lệ; chỉ cần trả lại None.

def myMethod(p: String) = Option(p).map(_.toLowerCase) 

Nếu bạn không thể tiếp tục khi không có giá trị, bạn cần xem xét liệu ngoại lệ thông tin có hữu ích hay không. Option(p).orElse(throw new IllegalArgumentException("Null!")) là một cách nhỏ gọn để thể hiện tình cảm ném ngoại lệ.

Trong Scala 2.10, bạn cũng có thể bọc mọi thứ trong scala.util.Try(...) sẽ tự động bắt và gói ngoại lệ cho bạn. Nếu bạn muốn có một ngoại lệ đóng gói thay vì một ngoại lệ, đây là cách để đi.(Và sử dụng Try thay vì Option.)

import scala.util.Try 
def myMethod(p: String) = Try(p.toLowerCase) 

Cuối cùng, để xử lý tổng quát hơn các kết quả thay thế, sử dụng Either. Quy ước xử lý lỗi là kết quả mong đợi là Right(whatever), trong khi Left(whatever) cho biết đã xảy ra sự cố.

+1

Vì tôi đang viết một API, tôi nghĩ cấu trúc thích hợp hơn là Thử. – j3d

+1

Hãy cẩn thận khi gói các giá trị null trong một Option mặc dù. Nếu bạn dựa vào suy luận kiểu, đôi khi bạn có thể gặp rắc rối. Ví dụ, nếu bạn chọn Option (null) .map (_ + 1) bạn sẽ được miễn trừ. Tuy nhiên, làm Option (null: String) .map (_. ToLowerCase) là tốt –

6

Có một số cách và cách của bạn là một.

Bạn cũng có thể sử dụng:

require(p != null, "p is null.") 

hoặc cách "thêm chức năng" sẽ được sử dụng Option:

def myMethod(p: String): Option[String] = { 

    // no exception 
    for { 
    pp <- Option(p) 
    } yield p + " foo bar" 
} 

chỉnh sửa:

hoặc nếu bạn muốn các lỗi mà không có một ngoại lệ được ném, bạn có thể sử dụng Either:

def myMethod(p: String): Either[Exception, String] = { 
    if(p == null) Left(new IllegalArgumentException("p is null.")) 
    else Right(p + "foo bar") 
} 
+2

Nó đặt ra câu hỏi; tại sao không chỉ có một phương pháp tham gia vào một Option [String]? –

+0

Đây là lý do tại sao scala là như vậy hơi say lên ngôn ngữ. Với tôi một Option trong chữ ký phương thức chỉ ra rằng tham số là tùy chọn. Điều gì nếu tham số không phải là tùy chọn và bạn không muốn người gọi vượt qua null hoặc trống (cuộc gọi đang sử dụng Java)? Đôi khi tôi tự hỏi tại sao mọi người không dính vào sự đơn giản và sử dụng Java/C++. Nó có thể tiết, nhưng nó có thể đọc được và đã nâng cao đủ tốt những ngày này để được sử dụng cho lập trình phân tán. – animageofmine

0

Thành ngữ Scala về cơ bản là "không sử dụng giá trị null bao giờ". Vì vậy, trừ khi bạn đang viết một API mà cần để chứa người dùng Java bẩn thỉu, tôi chỉ sẽ không lo lắng về nó. Nếu không, bạn sẽ kết thúc việc chèn kiểm tra boilerplate này cho mỗi tham số trên mọi phương thức bạn viết.

đẹp phương pháp một dòng của bạn

def square(x: String): String = math.pow(x.toInt, 2).toInt.toString 

sẽ biến thành một cái gì đó vụng về như

def square(x: String): String = 
    if (x == null) throw new NullPointerException() 
    math.pow(x.toInt, 2).toInt.toString 
} 

hoặc

def square(x: String): String = Option(x) match { 
    case Some(x) => math.pow(x.toInt, 2).toInt.toString 
    case None => throw new NullPointerException() 
} 

Làm thế nào khủng khiếp.

+0

'Double' là nguyên thủy. Nó không thể là 'null'. –

+0

Thay đổi nó thành một ví dụ mới với Strings :) –

+0

Không thể nói rằng trông đẹp hơn nữa .... –

0

phương pháp ưa thích của tôi là một cái gì đó như:

object HandlingInputValidation { 

    def main(args: Array[String]) = { 
    println("A1: " + handleInput("Correct ") + " END") 
    println("A2: " + handleInput("Correct") + " END") 
    println("A3: " + handleInput("") + " END") 
    println("A4: " + handleInput(" ") + " END") 
    println("A5: " + handleInput(null) + " END") 
    } 

    def handleInput(data: String): Option[String] = { 
    Option(data).map(_.trim.toLowerCase) 
    } 
} 

Trong trường hợp này, null sẽ None, và không gian sẽ được cắt.

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