Kiểm tra hai đối số trong Java, cả hai đều không null hoặc cả null


161

Tôi đã sử dụng boot mùa xuân để phát triển một dự án shell được sử dụng để gửi email, vd

sendmail -from foo@bar.com -password  foobar -subject "hello world"  -to aaa@bbb.com

Nếu thiếu frompasswordđối số, tôi sử dụng một người gửi và mật khẩu mặc định, ví dụ noreply@bar.com123456.

Vì vậy, nếu người dùng vượt qua fromđối số, họ cũng phải vượt qua passwordđối số và ngược lại. Điều đó có nghĩa là, cả hai đều không có giá trị hoặc cả hai đều là null.

Làm thế nào để tôi kiểm tra điều này một cách thanh lịch?

Bây giờ cách của tôi là

if ((from != null && password == null) || (from == null && password != null)) {
    throw new RuntimeException("from and password either both exist or both not exist");
}

14
Bên cạnh đó, lưu ý cách sử dụng khoảng trắng một cách cẩn thận giúp mã dễ đọc hơn rất nhiều - chỉ cần thêm khoảng trắng giữa các toán tử trong mã hiện tại của bạn sẽ thêm đáng kể vào IMO dễ đọc.
Jon Skeet

8
Vui lòng xác định "thanh lịch".
Đổi mới

Bạn cần một bộ đối số riêng cho thông tin xác thực SMTP và cho địa chỉ e-mail của người gửi phong bì. Các Fromđịa chỉ e-mail không phải lúc nào cũng tên xác thực SMTP.
Kaz

3
Nó thực sự không thể được tối ưu hóa nhiều hơn nữa, nó là một dòng mã có thể đọc được và không có gì có thể đạt được bằng cách tối ưu hóa nó.
diynevala

3
Lưu ý bên lề: nếu đây là tập lệnh shell, mật khẩu sẽ không được lưu trong lịch sử shell?
chạm vào cơ thể tôi vào

Câu trả lời:


331

Có một cách sử dụng toán tử ^( XOR ):

if (from == null ^ password == null) {
    // Use RuntimeException if you need to
    throw new IllegalArgumentException("message");
}

Điều ifkiện sẽ đúng nếu chỉ có một biến là null.

Nhưng tôi nghĩ thông thường tốt hơn là sử dụng hai ifđiều kiện với các thông báo ngoại lệ khác nhau. Bạn không thể xác định những gì đã sai bằng một điều kiện duy nhất.

if ((from == null) && (password != null)) {
    throw new IllegalArgumentException("If from is null, password must be null");
}
if ((from != null) && (password == null)) {
    throw new IllegalArgumentException("If from is not null, password must not be null");
}

Nó dễ đọc hơn và dễ hiểu hơn nhiều, và chỉ cần gõ thêm một chút.


152
Có một lý do tại sao xor trên hai bool thích hơn !=trên hai bool?
Eric Lippert

1
Ồ, tôi đã không nhận ra rằng XOR trên boolean giống như !=. Tâm trí. Và đó là một số lượng rất cao của upvote trong bình luận. Và, để thêm chất lượng cho nhận xét này, vâng, tôi cũng nghĩ rằng việc đưa ra thông báo lỗi khác nhau cho các trường hợp lỗi khác nhau là tốt hơn, vì người dùng sẽ biết rõ hơn cách sửa lỗi.
cần

1
Đối với 2 yếu tố là tốt. Làm thế nào để làm điều này với> 2 yếu tố?
Anushree Acharjee

Tôi muốn hiển thị thông báo lỗi nếu bất kỳ phần tử nào> 0. Theo mặc định, tất cả được đặt thành 0. Nếu tất cả đều> 0 thì đó là một kịch bản hợp lệ. làm như thế nào?
Anushree Acharjee

Điều này sẽ làm cho một câu hỏi phỏng vấn tiện lợi. Tôi tự hỏi những gì% lập trình viên biết nó. Nhưng tôi không đồng ý rằng nó không đủ rõ ràng và đảm bảo chia thành 2 ifmệnh đề - thông điệp trong các tài liệu ngoại lệ độc đáo (tôi đã chỉnh sửa câu hỏi, nhưng nó sẽ không xuất hiện cho đến khi được chấp nhận)
Adam

286

Chà, có vẻ như bạn đang cố kiểm tra xem điều kiện "vô hiệu" của hai người có giống nhau hay không. Bạn đã có thể sử dụng:

if ((from == null) != (password == null))
{
    ...
}

Hoặc làm cho nó rõ ràng hơn với các biến của trình trợ giúp:

boolean gotFrom = from != null;
boolean gotPassword = password != null;
if (gotFrom != gotPassword)
{
    ...
}

18
Bạn là một trong những người anh hùng SO của tôi @Kaz, nhưng không có gì nói 'cái này hay cái kia, nhưng không phải cả hai giống nhau' ^. :-)
David Bullock

6
@DavidBullock: Khi nói đến Booleans, không có gì nói "cái này hay cái kia nhưng không phải cả hai" giống như ... "không giống nhau"; XOR chỉ là một tên cho "không bằng" chức năng trên Booleans.
Kaz

5
@Kaz Chỉ là ^"Hey, toán hạng của tôi là booleans" theo cách !=không. (Mặc dù hiệu ứng này không may bị giảm đi do cần phải kiểm tra "toán hạng của tôi có thể là số và tôi có thể không phải là toán tử quan hệ tại thời điểm này", mà tôi cấp là một bất lợi). Tình trạng anh hùng của bạn không bị ảnh hưởng, mặc dù không đồng ý với tôi :-)
David Bullock

3
Sau khi đọc các yêu cầu của vấn đề, sau đó giải pháp của bạn, mã có ý nghĩa và có thể đọc được. Nhưng là một nhà phát triển trong 4 năm (vẫn còn đi học), đọc mã này sau đó cố gắng tìm ra "yêu cầu kinh doanh" là gì sẽ là một vấn đề đau đầu. Từ mã này, tôi không hiểu ngay lập tức " frompasswordcả hai phải là null hoặc cả hai đều không null". Có lẽ đó chỉ là tôi và thiếu kinh nghiệm của tôi, nhưng tôi thích giải pháp dễ đọc hơn như trong câu trả lời của @ stig-hemmer, ngay cả khi nó tốn thêm 3 dòng mã. Tôi đoán tôi không nhận được ngay lập tức bool != bool- nó không trực quan.
Chris Cirefice

2
@DavidBullock ^Toán tử là toán tử bitwise; nó thực sự không ngụ ý rằng toán hạng của nó là boolean. Toán tử boolean xor là xor.
Brilliand

222

Cá nhân, tôi thích đọc hơn thanh lịch.

if (from != null && password == null) {
    throw new RuntimeException("-from given without -password");
}
if (from == null && password != null) {
    throw new RuntimeException("-password given without -from");
}

52
+1 cho các tin nhắn tốt hơn. Điều này rất quan trọng, không ai thích viết tay "có gì đó không ổn" - tin nhắn giới thiệu, vì vậy không ai nên gây ra những tin nhắn như vậy. Tuy nhiên, trong thực tế, người ta nên thích một ngoại lệ cụ thể hơn (đặc biệt là IllegalArgumentExceptionthay vì trần RuntimeException)
Marco13

6
@matt có vẻ như lời phê bình của bạn không phải với mã, mà là với văn bản của các ngoại lệ. Nhưng tôi nghĩ rằng giá trị của câu trả lời này nằm ở cấu trúc của các câu lệnh if, chứ không phải trong nội dung của các thông báo lỗi. Đây là câu trả lời tốt nhất vì nó cải thiện chức năng; OP có thể dễ dàng thay thế bất kỳ chuỗi nào họ thích cho các văn bản ngoại lệ.
Dan Henderson

4
@matt Ưu điểm là có thể phân biệt trạng thái nào trong hai trạng thái không hợp lệ đã xảy ra và tùy chỉnh thông báo lỗi. Vì vậy, thay vì nói "bạn đã làm sai một trong hai điều sau", bạn có thể nói "bạn đã làm điều này" hoặc "bạn đã làm điều đó" (và sau đó tiếp tục cung cấp các bước giải quyết, nếu muốn). Độ phân giải có thể giống nhau trong cả hai trường hợp, nhưng không bao giờ nên nói "bạn đã làm một trong những điều này sai". Nguồn: trong một môi trường mà tôi không thể cung cấp chức năng này, tôi đã đưa ra nhiều câu hỏi từ những người dùng thỏa mãn điều kiện đầu tiên trong văn bản lỗi của tôi.
Dan Henderson

4
@DanHenderson> không bao giờ nên nói "bạn đã làm một trong những điều này sai." Tôi không đồng ý. Mật khẩu / Tên người dùng sẽ an toàn hơn khi chỉ nói tên người dùng và mật khẩu không khớp.
matt

2
@DanHenderson Từ quan điểm bảo mật, tốt hơn hết là không nên phân biệt giữa trường hợp tên người dùng có trong thư mục hay không nếu không kẻ tấn công có thể tìm ra tên người dùng hợp lệ. Tuy nhiên, trộn null / không null là (trong trường hợp này) luôn là lỗi sử dụng và hiển thị thông báo lỗi chi tiết hơn không làm rò rỉ thêm thông tin nào so với người dùng được cung cấp ở nơi đầu tiên.
siegi

16

Đặt chức năng đó trong phương thức 2 đối số bằng chữ ký:

void assertBothNullOrBothNotNull(Object a, Object b) throws RuntimeException

Điều này tiết kiệm không gian trong phương pháp thực tế mà bạn quan tâm và làm cho nó dễ đọc hơn. Không có gì sai với các tên phương thức hơi dài dòng và không có gì sai với các phương thức rất ngắn.


14
Không có không gian lưu so với ((from == null) != (password == null))đó là rất đơn giản để hiểu quá. Có một cái gì đó sai với các phương pháp không hữu ích.
edc65

3
Có một dòng cho câu lệnh if, dòng thứ hai cho câu lệnh throw và dòng thứ ba cho dấu ngoặc đóng: Tất cả được thay thế bằng một dòng. Thêm một dòng nữa nếu bạn cung cấp cho niềng răng một dòng mới!
Traubenfuchs

10
Khi đọc mã bạn có một tên phương thức bạn cần hiểu so với điều kiện tung hứng.
Traubenfuchs

1
chắc chắn +1, luôn thích trừu tượng hóa các chi tiết triển khai và các toán tử thực hiện với các phương thức mô tả và các tên biến làm cho INTENTION rõ ràng. logic chứa lỗi. ý kiến ​​thậm chí còn tồi tệ hơn. một tên phương thức thể hiện ý định và cô lập logic để dễ dàng tìm và sửa lỗi hơn. giải pháp này không yêu cầu người đọc biết hoặc suy nghĩ về bất kỳ cú pháp hoặc logic nào cả, nó cho phép chúng tôi tập trung vào YÊU CẦU KINH DOANH thay vào đó (đó là điều thực sự quan trọng)
sara

1
Bạn sẽ gặp rắc rối không cần thiết nếu bạn muốn có một số thông báo ngoại lệ mô tả ở đây.
Honza Brabec

11

Một giải pháp Java 8 sẽ được sử dụng Objects.isNull(Object), giả sử nhập tĩnh:

if (isNull(from) != isNull(password)) {
    throw ...;
}

Đối với Java <8 (hoặc nếu bạn không thích sử dụng Objects.isNull()), bạn có thể dễ dàng viết isNull()phương thức của riêng mình .


6
Đừng như vậy. from == null != password == nullgiữ tất cả trên cùng một khung của ngăn xếp, nhưng sử dụng Objects.isNull(Object)không cần đẩy và bật hai khung. Object.isNull (Object) có ở đó vì 'Phương thức này tồn tại được sử dụng như một Vị ngữ' (nghĩa là trong các luồng).
David Bullock

5
Một phương pháp đơn giản như thế này thường sẽ được JIT nhanh chóng đưa vào để tác động hiệu suất rất có thể không đáng kể. Chúng tôi thực sự có thể tranh luận về việc sử dụng Objects.isNull()- bạn có thể tự viết nếu bạn thích - nhưng khi có liên quan đến khả năng đọc tôi nghĩ rằng sử dụng isNull()là tốt hơn. Ngoài ra, bạn cần thêm dấu ngoặc đơn để biên dịch biểu thức đơn giản : from == null != (password == null).
Didier L

2
Tôi đồng ý về JIT'ing (và thứ tự các hoạt động ... Tôi lười biếng). Tuy nhiên, (val == null)rất rất nhiều cơ sở cung cấp với mục đích so sánh với null, tôi thấy khó để vượt qua hai lời gọi phương pháp chất béo lớn nhìn chằm chằm vào mặt tôi, ngay cả khi phương pháp này là khá chức năng, trong lineable, và nổi được đặt tên. Đó chỉ là tôi. Gần đây tôi đã quyết định rằng tôi hơi kỳ quặc.
David Bullock

4
Thành thật mà nói, ai quan tâm đến một khung stack duy nhất? ngăn xếp chỉ là vấn đề nếu bạn đang xử lý đệ quy (có thể là vô hạn) hoặc nếu bạn có ứng dụng 1000 tầng với biểu đồ đối tượng có kích thước của sa mạc sahara.
sara

9

Đây là một giải pháp chung cho bất kỳ số lượng kiểm tra null

public static int nulls(Object... objs)
{
    int n = 0;
    for(Object obj : objs) if(obj == null) n++;
    return n;
}

public static void main (String[] args) throws java.lang.Exception
{
    String a = null;
    String b = "";
    String c = "Test";

    System.out.println (" "+nulls(a,b,c));
}

Công dụng

// equivalent to (a==null & !(b==null|c==null) | .. | c==null & !(a==null|b==null))
if (nulls(a,b,c) == 1) { .. }

// equivalent to (a==null | b==null | c==null)
if (nulls(a,b,c) >= 1) { .. }

// equivalent to (a!=null | b!=null | c!=null)
if (nulls(a,b,c) < 3) { .. }

// equivalent to (a==null & b==null & c==null)
if (nulls(a,b,c) == 3) { .. }

// equivalent to (a!=null & b!=null & c!=null)
if (nulls(a,b,c) == 0) { .. }

2
Cách tiếp cận tốt, nhưng nhận xét "tương đương" đầu tiên của bạn là sai lầm khủng khiếp (ngoài lỗi chính tả tồn tại trong tất cả các nhận xét)
Ben Voigt

@BenVoigt Cảm ơn bạn đã thông báo, đã sửa ngay bây giờ
Khaled.K

9

Vì bạn muốn làm một cái gì đó đặc biệt (sử dụng mặc định) khi cả người gửi và mật khẩu đều vắng mặt, hãy xử lý trước.
Sau đó, bạn nên có cả người gửi và mật khẩu để gửi e-mail; ném một ngoại lệ nếu một trong hai là mất tích.

// use defaults if neither is provided
if ((from == null) && (password == null)) {
    from = DEFAULT_SENDER;
    password = DEFAULT_PASSWORD;
}

// we should have a sender and a password now
if (from == null) {
    throw new MissingSenderException();
}
if (password == null) {
    throw new MissingPasswordException();
}

Một lợi ích bổ sung là, nếu một trong hai mặc định của bạn là null, điều đó cũng sẽ được phát hiện.


Phải nói rằng, nói chung tôi nghĩ rằng việc sử dụng XOR nên được cho phép khi đó là toán tử bạn cần. Nó một phần của ngôn ngữ, không chỉ là một số mẹo hoạt động được do lỗi trình biên dịch phức tạp.
Tôi đã từng có một người chăn bò, người tìm thấy toán tử ternary quá khó hiểu để sử dụng ...


1
Bị từ chối vì tôi đã chọn ngẫu nhiên để lấy mẫu một trong những câu trả lời của bạn và không thể tìm thấy liên kết xkcd đã hứa! xấu hổ về bạn
dhein 15/03/2016

@Zaibis Trong phòng thủ của tôi, đó chỉ là một sở thích, không phải là một công việc toàn thời gian. Nhưng tôi sẽ xem liệu tôi có thể tìm thấy một ...
SQB

8

Tôi muốn đề xuất một phương án khác, đó là cách tôi thực sự viết đoạn mã này:

if( from != null )
{
    if( password == null )
        error( "password required for " + from );
}
else
{
    if( password != null )
        warn( "the given password will not be used" );
}

Đối với tôi đây dường như là cách tự nhiên nhất để diễn đạt tình trạng này, điều này giúp dễ hiểu cho những người có thể phải đọc nó trong tương lai. Nó cũng cho phép bạn đưa ra các thông báo chẩn đoán hữu ích hơn và coi mật khẩu không cần thiết là ít nghiêm trọng hơn và giúp dễ dàng sửa đổi, điều này có khả năng xảy ra đối với tình trạng như vậy. Tức là bạn có thể phát hiện ra rằng việc cung cấp mật khẩu làm đối số dòng lệnh không phải là ý tưởng tốt nhất và có thể muốn cho phép đọc mật khẩu từ đầu vào tiêu chuẩn tùy chọn nếu thiếu đối số. Hoặc bạn có thể muốn âm thầm bỏ qua đối số mật khẩu không cần thiết. Những thay đổi như thế này sẽ không yêu cầu bạn viết lại toàn bộ.

Bên cạnh đó, nó chỉ thực hiện số lượng so sánh tối thiểu, do đó, nó không đắt hơn các lựa chọn thay thế "thanh lịch" hơn. Mặc dù hiệu suất rất khó xảy ra ở đây vì bắt đầu một quy trình mới đắt hơn nhiều so với kiểm tra null.


Tôi nhận xét một chút về cuộc trò chuyện, vì vậy tôi có thể theo dõi người khác bằng "// chúng tôi có null từ". Sự ngắn gọn của ví dụ làm cho điều này thực sự nhỏ. Tôi thích sự rõ ràng của logic và giảm các bài kiểm tra này.
Nate

Điều này hoạt động hoàn toàn tốt, nhưng lồng nhau nếu các tuyên bố dường như ít rõ ràng hơn và lộn xộn hơn với tôi. Tuy nhiên, đó chỉ là ý kiến ​​cá nhân, vì vậy tôi rất vui vì câu trả lời này có ở đây như một lựa chọn khác
Kevin Wells

Theo như sự thanh lịch, đây có lẽ là một trong những cách kém thanh lịch nhất để làm điều này.
kịch

7

Tôi nghĩ rằng một cách chính xác để xử lý vấn đề này là xem xét ba tình huống: cả 'từ' và 'mật khẩu' đều được cung cấp, không được cung cấp, cả hai đều được cung cấp.

if(from != null && password != null){
    //use the provided values
} else if(from == null && password == null){
    //both values are null use the default values
} else{
   //throw an exception because the input is not correct.
}

Nghe có vẻ như câu hỏi ban đầu muốn phá vỡ dòng chảy nếu đó là đầu vào không chính xác, nhưng sau đó họ sẽ phải lặp lại một số logic sau đó. Có lẽ một tuyên bố ném tốt có thể là:

throw new IllegalArgumentException("form of " + form + 
    " cannot be used with a "
    + (password==null?"null":"not null") +  
    " password. Either provide a value for both, or no value for both"
);

2
Mã này sai không phải vì nó không hoạt động mà vì nó rất khó hiểu. Gỡ lỗi loại mã đó, được viết bởi người khác, chỉ là một cơn ác mộng.
NO_NAME

2
@NO_NAME Tôi không thấy lý do tại sao nó khó hiểu. OP đã cung cấp ba trường hợp: Khi cả hai hình thức và mật khẩu được cung cấp, khi không ai được cung cấp và trường hợp hỗn hợp sẽ đưa ra một ngoại lệ. Bạn đang đề cập đến điều kiện giữa để kiểm tra xem cả hai đều null?
matt

2
Tôi đồng ý với @NO_NAME, trường hợp giữa đó mất quá nhiều phân tích cú pháp để lướt qua. Trừ khi bạn phân tích dòng trên cùng, bạn sẽ không nhận được rằng null có liên quan gì đến giữa. Sự bình đẳng từ và mật khẩu trong trường hợp đó thực sự chỉ là tác dụng phụ của việc không có giá trị.
jimm101

1
@ jimm101 Vâng, tôi có thể thấy đó là một vấn đề. Lợi ích hiệu suất sẽ là tối thiểu / không thể phát hiện đối với một giải pháp dài dòng hơn. Tôi không chắc đó là vấn đề gì. Ill cập nhật nó.
matt

2
@matt Có thể không có lợi ích về hiệu năng - không rõ trình biên dịch sẽ làm gì và chip sẽ lấy gì từ bộ nhớ trong trường hợp này. Rất nhiều chu trình lập trình viên có thể được ghi vào các tối ưu hóa mà không thực sự mang lại bất cứ điều gì.
jimm101

6

Đây là một cách tương đối đơn giản mà không liên quan đến bất kỳ if dài nào của Xor. Tuy nhiên, nó đòi hỏi bạn phải dài dòng hơn một chút, nhưng về mặt ưu điểm, bạn có thể sử dụng Ngoại lệ tùy chỉnh mà tôi đề xuất để nhận thông báo lỗi có ý nghĩa hơn.

private void validatePasswordExists(Parameters params) {
   if (!params.hasKey("password")){
      throw new PasswordMissingException("Password missing");
   }
}

private void validateFromExists(Parameters params) {
   if (!params.hasKey("from")){
      throw new FromEmailMissingException("From-email missing");
   }
}

private void validateParams(Parameters params) {

  if (params.hasKey("from") || params.hasKey("password")){
     validateFromExists(params);
     validatePasswordExists(params);
  }
}

1
bạn không nên sử dụng ngoại lệ thay cho câu lệnh điều khiển. Bên cạnh việc là một hit hiệu năng, quan trọng hơn là nó làm giảm khả năng đọc mã của bạn bởi vì nó phá vỡ dòng chảy tinh thần.
một phu phu

1
@anphu Không. Chỉ là không. Sử dụng các ngoại lệ làm tăng khả năng đọc mã vì nó được loại bỏ các mệnh đề if-other và làm cho dòng mã rõ ràng hơn. docs.oracle.com/javase/tutorial/essential/exceptions/ từ
Arnab Datta

1
Tôi nghĩ rằng bạn đang nhầm lẫn một cái gì đó thực sự đặc biệt so với một cái gì đó xảy ra thường xuyên và có thể được coi là một phần của thực thi bình thường. Tài liệu java sử dụng các ví dụ đặc biệt tức là hết bộ nhớ trong khi đọc tệp; Gặp thông số không hợp lệ không phải là ngoại lệ. "Không sử dụng ngoại lệ cho luồng kiểm soát bình thường." - blog.msdn.com/b/kcwalina/archive/2005/03/16/396787.aspx
một phu nhân

Chà, đầu tiên: nếu các đối số thiếu / thích hợp không phải là ngoại lệ, tại sao IllegalArgumentException thậm chí còn tồn tại? Thứ hai: nếu bạn thực sự tin rằng các đối số không hợp lệ không phải là ngoại lệ, thì cũng không nên xác thực nó. Nói cách khác, chỉ cần cố gắng thực hiện hành động và khi có sự cố xảy ra, sau đó ném một ngoại lệ. Cách tiếp cận này là tốt, nhưng hình phạt hiệu suất mà bạn đang nói đến phát sinh ở đây, không phải trong cách tiếp cận tôi đề xuất. Các ngoại lệ Java không chậm khi ném; đó là stacktrace cần có thời gian để phục hồi.
Arnab Datta

Bối cảnh là chìa khóa. Trong ngữ cảnh của OP (ứng dụng sendmail), việc quên tên người dùng và mật khẩu là phổ biến và được mong đợi. Trong thuật toán hướng dẫn tên lửa, một tham số tọa độ null sẽ ném ngoại lệ. Tôi không nói không xác nhận params. Trong ngữ cảnh của OP, tôi đã nói không sử dụng ngoại lệ để điều khiển logic ứng dụng. Unwinding the stacktrace là bản hit hoàn hảo mà tôi đang nói đến. Sử dụng phương pháp của bạn, cuối cùng bạn sẽ bắt được PasswordMissingException / FromEmailMissingException tức là thư giãn, hoặc tệ hơn, hãy để nó được xử lý. .
một phu phu

6

Dường như không ai đề cập đến toán tử ternary :

if (a==null? b!=null:b==null)

Hoạt động độc đáo để kiểm tra điều kiện đặc biệt này, nhưng không khái quát quá hai biến.


1
Trông đẹp, nhưng khó hiểu hơn ^, !=với hai bool hoặc hai ifs
coolguy

@coolguy Tôi đoán là toán tử ternary phổ biến hơn nhiều so với toán tử XOR (không đề cập đến 'sự bất ngờ về tinh thần' mỗi khi bạn thấy XOR trong mã không thực hiện các thao tác bit) và công thức này có xu hướng tránh bị cắt và dán các lỗi làm hỏng gấp đôi nếu.
gbronner

Không được khuyến khích. Điều này sẽ không khác biệt giữa (a! = Null && b == null) và (a == null && b! = Null). Nếu bạn định sử dụng toán tử ternary:a == null ? (b == null? "both null" : "a null while b is not") : (b ==null? "b null while a is not")
Arnab Datta

5

Theo tôi thấy ý định của bạn, không cần phải luôn luôn kiểm tra cả hai giá trị độc quyền mà chỉ kiểm tra xem có phải passwordlà null hay không và nếu fromkhông phải là null. Bạn có thể bỏ qua passwordđối số đã cho và sử dụng mặc định của riêng bạn nếu fromlà null.

Viết bằng giả phải như thế này:

if (from == null) { // form is null, ignore given password here
    // use your own defaults
} else if (password == null) { // form is given but password is not
    // throw exception
} else { // both arguments are given
    // use given arguments
}

4
Vấn đề duy nhất với điều này là khi người dùng cung cấp passwordmà không cung cấp from, thì họ có thể có ý định ghi đè mật khẩu, nhưng vẫn giữ tài khoản mặc định. Nếu người dùng làm điều đó, đó là một hướng dẫn không hợp lệ và họ nên được nói như vậy. Chương trình không nên tiến hành như thể đầu vào là hợp lệ, và tiếp tục và cố gắng sử dụng tài khoản mặc định với mật khẩu mà người dùng không chỉ định. Tôi thề ở các chương trình như thế.
David Bullock

4

Tôi ngạc nhiên không ai đề cập đến giải pháp đơn giản về việc tạo frompasswordcác trường của một lớp và chuyển một tham chiếu đến một thể hiện của lớp đó:

class Account {
    final String name, password;
    Account(String name, String password) {
        this.name = Objects.requireNonNull(name, "name");
        this.password = Objects.requireNonNull(password, "password");
    }
}

// the code that requires an account
Account from;
// do stuff

Đây from có thể là null hoặc không null và nếu nó không null, cả hai trường của nó đều có giá trị khác null.

Một ưu điểm của phương pháp này là lỗi tạo một trường nhưng không phải trường khác null được kích hoạt ở nơi tài khoản ban đầu được lấy, không phải khi mã sử dụng tài khoản chạy. Vào thời điểm mã sử dụng tài khoản được thực thi, dữ liệu không thể không hợp lệ.

Một ưu điểm khác của phương pháp này là dễ đọc hơn vì nó cung cấp nhiều thông tin ngữ nghĩa hơn. Ngoài ra, có thể bạn yêu cầu tên và mật khẩu cùng nhau ở những nơi khác, do đó, chi phí xác định một lớp bổ sung sẽ được khấu hao theo nhiều cách sử dụng.


Nó không hoạt động như mong đợi vì new Account(null, null)sẽ ném NPE mặc dù Tài khoản có cả tên và mật khẩu null vẫn hợp lệ.
HiếuHT

Ý tưởng là để vượt qua null nếu tên và mật khẩu là null, dù trong thế giới thực bạn có nói tài khoản tồn tại hay không.
Phục hồi Monica

Những gì tôi nhận được từ OP là có nghĩa là, cả hai đều không null hoặc cả hai đều là null. Tôi chỉ tự hỏi làm thế nào bạn có thể tạo một đối tượng Tài khoản với cả tên và mật khẩu null?
HiếuHT

@HieuHT Xin lỗi, bình luận cuối cùng của tôi không rõ ràng. Nếu tên và mật khẩu là null, bạn sẽ sử dụng nullthay vì một Account. Bạn sẽ không chuyển nullđến nhà Accountxây dựng.
Phục hồi Monica
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.