Java có hỗ trợ các giá trị tham số mặc định không?


1661

Tôi đã xem qua một số mã Java có cấu trúc sau:

public MyParameterizedFunction(String param1, int param2)
{
    this(param1, param2, false);
}

public MyParameterizedFunction(String param1, int param2, boolean param3)
{
    //use all three parameters here
}

Tôi biết rằng trong C ++ tôi có thể gán một tham số một giá trị mặc định. Ví dụ:

void MyParameterizedFunction(String param1, int param2, bool param3=false);

Java có hỗ trợ loại cú pháp này không? Có bất kỳ lý do tại sao cú pháp hai bước này là thích hợp hơn?


85
Không. Tuy nhiên, mẫu Builder có thể giúp.
Dave Jarvis

50
Tôi thực sự nhớ tính năng này. Nó giúp ích rất nhiều khi sửa đổi mã hiện có để lấy tham số bổ sung cho hàm hoặc hàm tạo
Jatin

4
@Jatin Với tái cấu trúc "Thay đổi chữ ký phương thức" của Eclipse, bạn có thể thêm một tham số và cung cấp một giá trị mặc định mà những kẻ xâm lược hiện tại sẽ sử dụng.
Erwin Bolwidt

2
@ErwinBolwidt Cảm ơn. Tôi đang sử dụng Android Studio và nó cũng có tùy chọn cấu trúc lại phương thức và cung cấp các giá trị mặc định. Khá hữu dụng.
Jatin

3
@t tạm_user_name public MyParameterizedFunction(String param1, int param2)là một hàm tạo, không phải là phương thức, khai báo.
Mario Ishac

Câu trả lời:


955

Không, cấu trúc bạn tìm thấy là cách Java xử lý nó (nghĩa là, với quá tải thay vì các tham số mặc định).

Đối với các nhà xây dựng, hãy xem Java hiệu quả: Mẹo Mục 1 của Hướng dẫn ngôn ngữ lập trình (Xem xét các phương thức nhà máy tĩnh thay vì các nhà xây dựng) nếu quá tải đang trở nên phức tạp. Đối với các phương thức khác, đổi tên một số trường hợp hoặc sử dụng một đối tượng tham số có thể giúp ích. Đây là khi bạn có đủ độ phức tạp mà việc phân biệt là khó khăn. Một trường hợp xác định là nơi bạn phải phân biệt bằng cách sử dụng thứ tự của các tham số, không chỉ số lượng và loại.



135
@JarrodRoberson: Phương pháp nhà máy tĩnh không gây hại nhiều hơn new. Chúng được sử dụng tất cả các thời gian trong mã mới. Các nhà xây dựng cho các đối tượng giá trị đơn giản thường là kết quả của kỹ thuật quá mức.
Lii

12
@JarrodRoberson: Cách thú vị để buộc sử dụng đúng thông qua trình biên dịch, cảm ơn vì đã chia sẻ! Gợi ý thân thiện cho các bài đăng trong tương lai: 300 dòng mã nguồn không bị lỗi có lẽ hơi khó tiêu hóa đối với hầu hết mọi người (rốt cuộc, mã khó đọc hơn viết). Cảm ơn một lần nữa!
Christian Aichinger

17
@JarrodRoberson: Rất vui, mong chờ điều đó! Điều tôi muốn truyền đạt: với tư cách là người đọc blog của bạn, một ví dụ 50 dòng với mô tả văn bản ngắn gọn về những gì đang diễn ra sẽ giúp tôi hơn 300 dòng không có ngữ cảnh.
Christian Aichinger

8
@ user177800 Không đồng ý - Các phương thức tĩnh nếu được viết dưới dạng các hàm thuần túy là hoàn toàn tốt. Đó là khi một hàm tĩnh đột biến nói rằng chúng trở thành một vấn đề ...
Levi Fuller

642

Không, nhưng bạn có thể sử dụng Mẫu xây dựng , như được mô tả trong câu trả lời Stack Overflow này .

Như được mô tả trong câu trả lời được liên kết, Mẫu Builder cho phép bạn viết mã như

Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
                 .name("Spicoli")
                 .age(16)
                 .motto("Aloha, Mr Hand")
                 .buildStudent();

trong đó một số trường có thể có giá trị mặc định hoặc mặt khác là tùy chọn.


142
Cuối cùng, ví dụ tuyệt vời ít hơn 2 trang của mẫu Builder.
nevvermind

14
Mặc dù tôi tò mò, tại sao chúng ta cần một lớp trình xây dựng khi sử dụng mẫu trình xây dựng. Tôi đã nghĩ về Student s1 = new Student (). Name ("Spicolo"). Tuổi (16) .motto ("Aloha, Mr Hand);
ivanceras

52
@ivanceras: Nó có liên quan khi các lớp có các trường bắt buộc và bạn không muốn có thể khởi tạo các lớp đó ở trạng thái không hợp lệ. Vì vậy, nếu bạn vừa nói Student s1 = new Student().age(16);thì điều đó sẽ để lại cho bạn một Học sinh không có tên, điều đó có thể là xấu. Nếu nó không tệ, thì giải pháp của bạn là tốt.
Eli Courtwright

57
@ivanceras: một lý do khác là bạn có thể muốn lớp của mình trở nên bất biến sau khi xây dựng, vì vậy bạn sẽ không muốn các phương thức trong đó thay đổi giá trị của nó.
Jules

3
@ivanceras: Tôi đã sử dụng Trình xây dựng cho 3 điều - loại bỏ nhiều đối số và khởi tạo trôi chảy, không thay đổi và quan trọng nhất là tôi cảm thấy xác thực đối tượng miền trong phương thức build (). Các phương thức xuất xưởng như trong trường hợp trên buildFreshman (), buildSenior () v.v.
Abhijeet Kushe

485

Có một số cách để mô phỏng các tham số mặc định trong Java:

  1. Phương pháp quá tải.

    void foo(String a, Integer b) {
        //...
    }
    
    void foo(String a) {
        foo(a, 0); // here, 0 is a default value for b
    }
    
    foo("a", 2);
    foo("a");

    Một trong những hạn chế của phương pháp này là nó không hoạt động nếu bạn có hai tham số tùy chọn cùng loại và bất kỳ tham số nào trong số chúng có thể được bỏ qua.

  2. Biến thể.

    a) Tất cả các tham số tùy chọn là cùng loại:

    void foo(String a, Integer... b) {
        Integer b1 = b.length > 0 ? b[0] : 0;
        Integer b2 = b.length > 1 ? b[1] : 0;
        //...
    }
    
    foo("a");
    foo("a", 1, 2);

    b) Các loại tham số tùy chọn có thể khác nhau:

    void foo(String a, Object... b) {
        Integer b1 = 0;
        String b2 = "";
        if (b.length > 0) {
          if (!(b[0] instanceof Integer)) { 
              throw new IllegalArgumentException("...");
          }
          b1 = (Integer)b[0];
        }
        if (b.length > 1) {
            if (!(b[1] instanceof String)) { 
                throw new IllegalArgumentException("...");
            }
            b2 = (String)b[1];
            //...
        }
        //...
    }
    
    foo("a");
    foo("a", 1);
    foo("a", 1, "b2");

    Hạn chế chính của phương pháp này là nếu các tham số tùy chọn thuộc các loại khác nhau, bạn sẽ mất kiểm tra kiểu tĩnh. Hơn nữa, nếu mỗi tham số có ý nghĩa khác nhau, bạn cần một số cách để phân biệt chúng.

  3. Nulls. Để giải quyết các hạn chế của các cách tiếp cận trước đó, bạn có thể cho phép các giá trị null và sau đó phân tích từng tham số trong thân phương thức:

    void foo(String a, Integer b, Integer c) {
        b = b != null ? b : 0;
        c = c != null ? c : 0;
        //...
    }
    
    foo("a", null, 2);

    Bây giờ tất cả các giá trị đối số phải được cung cấp, nhưng các giá trị mặc định có thể là null.

  4. Lớp học tùy chọn. Cách tiếp cận này tương tự như null, nhưng sử dụng lớp Tùy chọn Java 8 cho các tham số có giá trị mặc định:

    void foo(String a, Optional<Integer> bOpt) {
        Integer b = bOpt.isPresent() ? bOpt.get() : 0;
        //...
    }
    
    foo("a", Optional.of(2));
    foo("a", Optional.<Integer>absent());

    Tùy chọn làm cho một hợp đồng phương thức rõ ràng cho một người gọi, tuy nhiên, người ta có thể thấy chữ ký đó quá dài dòng.

  5. Mô hình xây dựng. Mẫu trình xây dựng được sử dụng cho các nhà xây dựng và được triển khai bằng cách giới thiệu một lớp Builder riêng biệt:

     class Foo {
         private final String a; 
         private final Integer b;
    
         Foo(String a, Integer b) {
           this.a = a;
           this.b = b;
         }
    
         //...
     }
    
     class FooBuilder {
       private String a = ""; 
       private Integer b = 0;
    
       FooBuilder setA(String a) {
         this.a = a;
         return this;
       }
    
       FooBuilder setB(Integer b) {
         this.b = b;
         return this;
       }
    
       Foo build() {
         return new Foo(a, b);
       }
     }
    
     Foo foo = new FooBuilder().setA("a").build();
  6. Bản đồ. Khi số lượng tham số quá lớn và đối với hầu hết chúng, các giá trị mặc định thường được sử dụng, bạn có thể truyền các đối số phương thức dưới dạng bản đồ tên / giá trị của chúng:

    void foo(Map<String, Object> parameters) {
        String a = ""; 
        Integer b = 0;
        if (parameters.containsKey("a")) { 
            if (!(parameters.get("a") instanceof Integer)) { 
                throw new IllegalArgumentException("...");
            }
            a = (String)parameters.get("a");
        } else if (parameters.containsKey("b")) { 
            //... 
        }
        //...
    }
    
    foo(ImmutableMap.<String, Object>of(
        "a", "a",
        "b", 2, 
        "d", "value")); 

Xin lưu ý rằng bạn có thể kết hợp bất kỳ phương pháp nào trong số những phương pháp này để đạt được kết quả mong muốn.


1
Lời giải thích hay. Tôi chưa bao giờ thấy các giá trị trả về được sử dụng như thế này. Cho 5) làm return thisgì? Ngoài ra, không phải FooBuilder().setA("a").build();vì (theo định nghĩa) hàm tạo được gọi đầu tiên và FooBuilder()trả về một giá trị, điều này có nghĩa là .setA("a"):không có cơ hội được gọi?
Celeritas

3
@Celeritas return thistrả về cùng một đối tượng mà phương thức được gọi (trong ví dụ này FooBuilder). Điều này cho phép xâu chuỗi các phương thức trong một câu lệnh hoạt động trên cùng một đối tượng: new FooBuilder().setA(..).setB(..).setC(..)vv trái ngược với việc gọi từng phương thức trong một câu lệnh riêng biệt.
ADTC

2
@Celeritas new FooBuilder()trả về một FooBuilderđối tượng mà setAphương thức được gọi. Như setBkhông được gọi, this.bgiữ lại giá trị mặc định. Cuối cùng buildphương thức được gọi trên FooBuilderđối tượng này . Các buildphương pháp tạo ra và trả về một Foođối tượng mà được thiết lập để biến Foo foo. Lưu ý rằng FooBuilderđối tượng không được lưu trữ trong bất kỳ biến nào.
ADTC

Chú thích cũng có thể được sử dụng để tạo các tham số mặc định và hữu ích nhất khi được yêu cầu cho các bộ sưu tập đa hình. docs.oracle.com/javase/tutorial/java/annotations/declaring.html
Martin Spamer

1
Hơn 900 câu hỏi trên cùng một câu trả lời qua hai câu hỏi. Tôi rất ấn tượng: stackoverflow.com/questions/965690/java-optional-parameter
21

256

Thật đáng buồn không.


34
Có buồn không Làm như vậy sẽ giới thiệu chữ ký chức năng mơ hồ.
Trey

69
@Trey: các ngôn ngữ có tham số mặc định thường bỏ qua chức năng quá tải vì nó ít hấp dẫn hơn. Vì vậy, không có sự mơ hồ. Bên cạnh đó, Scala đã thêm tính năng này vào 2.8 và bằng cách nào đó đã giải quyết vấn đề không rõ ràng (vì chúng giữ quá tải vì lý do tương thích).
PhiLho

32
Tôi không thấy cách mặc định tham số ngăn quá tải chức năng. Ví dụ, C # cho phép ghi đè và cũng cho phép khởi tạo mặc định. Có vẻ như sự lựa chọn tùy ý, không hạn chế là lý do.
FlavorScape

51
Vâng, hãy đánh đổi làm cho trình biên dịch thực hiện một số công việc bổ sung và thay vào đó làm cho tất cả chúng ta viết 100000 quá tải để cung cấp cho người dùng thư viện của chúng tôi thuận tiện. Ý tưởng tốt.

28
@ user562566: Bất cứ khi nào tôi làm việc trong một dự án Java, tôi đều có ấn tượng rằng các nhà phát triển Java được trả tiền / được đo bằng bao nhiêu dòng mã họ tạo ra mỗi ngày
Mark K Cowan

83

Không may là đúng vậy.

void MyParameterizedFunction(String param1, int param2, bool param3=false) {}

có thể được viết bằng Java 1.5 như:

void MyParameterizedFunction(String param1, int param2, Boolean... params) {
    assert params.length <= 1;
    bool param3 = params.length > 0 ? params[0].booleanValue() : false;
}

Nhưng bạn có nên hay không phụ thuộc vào cách bạn cảm nhận về trình biên dịch tạo ra một

new Boolean[]{}

cho mỗi cuộc gọi.

Đối với nhiều tham số mặc định:

void MyParameterizedFunction(String param1, int param2, bool param3=false, int param4=42) {}

có thể được viết bằng Java 1.5 như:

void MyParameterizedFunction(String param1, int param2, Object... p) {
    int l = p.length;
    assert l <= 2;
    assert l < 1 || Boolean.class.isInstance(p[0]);
    assert l < 2 || Integer.class.isInstance(p[1]);
    bool param3 = l > 0 && p[0] != null ? ((Boolean)p[0]).booleanValue() : false;
    int param4 = l > 1 && p[1] != null ? ((Integer)p[1]).intValue() : 42;
}

Điều này phù hợp với cú pháp C ++, chỉ cho phép các tham số mặc định ở cuối danh sách tham số.

Ngoài cú pháp, có một sự khác biệt trong đó điều này đã chạy kiểm tra loại thời gian cho các tham số mặc định được thông qua và loại C ++ kiểm tra chúng trong quá trình biên dịch.


14
Thông minh, nhưng varargs (...) chỉ có thể được sử dụng cho tham số cuối cùng, điều này hạn chế hơn những ngôn ngữ hỗ trợ các tham số mặc định cung cấp cho bạn.
RèmDog

6
đó là thông minh nhưng hơi lộn xộn so với phiên bản C ++
Ai đó ở đâu đó vào

5
Java chắc chắn cần các tham số mặc định tùy chọn vì C # và các tham số khác cho phép ... cú pháp là hiển nhiên và tôi cho rằng họ có thể thực hiện điều này khá đơn giản ngay cả khi chỉ cần biên dịch tất cả các kết hợp có thể ... Tôi không thể tưởng tượng được tại sao họ không thêm nó vào ngôn ngữ chưa!
jwl

10
Không bao giờ nên sử dụng một assertmã sản xuất. Ném một ngoại lệ.
Michael Dorst

5
-1 Đây thực sự không phải là những gì varargs dành cho. Đây là một hack. - trong trường hợp này, việc sử dụng quá tải sẽ dễ đọc hơn (điều này thật đáng tiếc, vì ba ký tự phụ dễ đọc hơn 5 dòng nguồn bổ sung ...). - nhưng Java không hỗ trợ các tham số mặc định.
BrainSlugs83

38

Không, nhưng bạn có thể rất dễ dàng mô phỏng chúng. Những gì trong C ++ là:

public: void myFunction(int a, int b=5, string c="test") { ... }

Trong Java, nó sẽ là một hàm quá tải:

public void myFunction(int a, int b, string c) { ... }

public void myFunction(int a, int b) {
    myFunction(a, b, "test");
}

public void myFunction(int a) {
    myFunction(a, 5);
}

Trước đó đã được đề cập, các tham số mặc định đó gây ra các trường hợp mơ hồ trong quá tải chức năng. Điều đó chỉ đơn giản là không đúng sự thật, chúng ta có thể thấy trong trường hợp của C ++: có, nó có thể tạo ra các trường hợp mơ hồ, nhưng những vấn đề này có thể dễ dàng xử lý. Nó đơn giản là không được phát triển trong Java, có lẽ bởi vì những người sáng tạo muốn có một ngôn ngữ đơn giản hơn nhiều như C ++ - nếu họ có quyền, là một câu hỏi khác. Nhưng hầu hết chúng ta không nghĩ rằng anh ta sử dụng Java vì tính đơn giản của nó.


8
Ý tưởng chính của ký hiệu giá trị mặc định C # là chính xác để tránh mã hóa bản tóm tắt này và chỉ có một hàm tạo thay vì nhiều hàm.
Kolya Ivankov

1
@KolyaIvankov Tôi không biết C #, nhưng tôi biết C ++ trong đó lý do là như nhau. Tôi không biết cái gì là tốt hơn, nhưng tôi nghĩ, thực ra cùng một mã soạn sẵn được trình biên dịch tạo ra trong trường hợp C ++ / C # và nó sẽ đi vào nhị phân cuối cùng.
peterh - Phục hồi Monica

5
Mỗi ngôn ngữ lập trình là (đặc biệt) là một phương tiện để tránh một chương trình soạn thảo chương trình lắp ráp, tôi có sai không? Câu hỏi chỉ là liệu nó có cung cấp một chức năng tiện dụng hay không.
Kolya Ivankov

2
Câu đầu tiên là một câu hỏi tu từ. Từ "câu hỏi" trong câu thứ hai không liên quan gì đến câu hỏi tu từ trong câu thứ nhất.
Kolya Ivankov

1
Cụ thể hơn: ngôn ngữ là công cụ cho phép chúng ta viết chương trình theo cách chúng ta có thể kiểm soát những gì được viết, biên dịch là một cách để nói với máy những gì chúng ta muốn từ nó. Một công cụ hữu ích hơn nếu nó cho phép chúng ta tránh nồi hơi. Trong thực tế, gnavi đã hỏi, nếu họ có thể tránh chính xác loại mã soạn sẵn mà bạn đề xuất như một câu trả lời, vì C # cho phép nó.
Kolya Ivankov

24

Bạn có thể làm điều này là trong Scala, chạy trên JVM và tương thích với các chương trình Java. http://www.scala-lang.org/

I E

class Foo(var prime: Boolean = false, val rib: String)  {}

58
Mang ngôn ngữ hoàn toàn mới để có được một tính năng không phổ biến?
om-nom-nom

8
@ om-nom-nom: Java không bao giờ tồn tại. Nói rằng một tính năng không được sử dụng là tương đương mà không ai cần nói rằng Java không phổ biến trước khi nó được phát minh có nghĩa là Gosling không nên bắt đầu thiết kế nó.
Val

28
@Val chỉ nói rằng điều này giống như bắn chim bằng đại bác
om-nom-nom

8
điều đó không liên quan gì đến câu hỏi của OP
Destan 7/11/2016

Hoạt động trong Kotlin, quá. Và Groovy. Và C#. Và Javascript. Và hầu hết tất cả các ngôn ngữ khác được tạo ra cho những người thực sự và các vấn đề.
spyro

17

Không , nhưng cách đơn giản nhất để thực hiện điều này là:

public myParameterizedFunction(String param1, int param2, Boolean param3) {

    param3 = param3 == null ? false : param3;
}

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}

hoặc thay vì toán tử ternary , bạn có thể sử dụng if:

public myParameterizedFunction(String param1, int param2, Boolean param3) {

    if (param3 == null) {
        param3 = false;
    }
}

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}

2
Vâng, phương pháp này dường như là tốt nhất từ ​​các lựa chọn thay thế khác. Tuy nhiên, sẽ rất tốt nếu Java chấp nhận các giá trị mặc định; Kotlin đã chỉ ra rằng điều này có thể được thực hiện, vì vậy tôi không chắc tại sao Oracle không bước vào kỷ nguyên hiện đại và tiếp tục thiết kế java như thể đó là những năm 1990. : D
shevy

13

Tôi có thể nói rõ điều này ở đây nhưng tại sao không tự mình thực hiện tham số "mặc định"?

public class Foo() {
        public void func(String s){
                func(s, true);
        }
        public void func(String s, boolean b){
                //your code here
        }
}

mặc định, bạn sẽ sử dụng

func("my string");

và nếu bạn không muốn sử dụng mặc định, bạn sẽ sử dụng

func("my string", false);

11
Người đăng đã hỏi liệu mẫu này (khá xấu xí) có thể tránh được không ... ;-) Trong các ngôn ngữ hiện đại hơn (như c #, Scala), bạn không cần quá tải thêm mà chỉ tạo ra nhiều dòng mã hơn. Đến một lúc nào đó, bạn có thể sử dụng varargs trong khi đó (static int max (int ... mảng) {}), nhưng chúng chỉ là một cách giải quyết rất xấu.
Offler

2
Quá tải không phải là xấu và có nhiều lợi ích, chẳng hạn như các cuộc gọi phương thức khác nhau với các chữ ký khác nhau có thể thực hiện chức năng khác nhau. //This is better public class Foo() { /* This does something */ public void func(String s){ //do something } /* This does something else with b */ public void func(String s, boolean b){ // b was passed } } //Than this public class Foo() { /* This does something unless b = value, then it does something else */ public void func(String s, boolean b = value){ If (b){ // Do Something } else{ // Do something else } } }
Gian hàng Antony

Vâng, nếu một người muốn hành vi khác nhau. Nếu sự khác biệt duy nhất là một thay đổi nhỏ trong tính toán, v.v., chắc chắn sẽ lãng phí công sức để tạo nhiều chữ ký. Mặc định có ý nghĩa khi bạn cần chúng ... và thiếu nó không nên được phân loại là một yêu cầu "vô dụng".
Kapil

Các tham số mặc định @ Offerler không liên quan gì đến "ngôn ngữ hiện đại". Tôi đã sử dụng chúng trong Delphi 20 năm trước và có lẽ chúng đã tồn tại trong Turbo Pascal.
Không thể tin được vào ngày 1 tháng

Tôi đồng ý với Offler và không đồng ý với Antony booth. Tôi thấy nó không chỉ xấu mà còn khá kém hiệu quả. Các ngôn ngữ như ruby ​​hoặc python khiến việc sử dụng các tham số mặc định trở nên tầm thường; Tôi đoán những gì Java yêu cầu bạn làm là tìm (và sử dụng) cách giải quyết. Kiểm tra rõ ràng so với null dường như là sự lựa chọn ít xấu xí nhất, vì tôi cũng có thể gọi nó từ dòng lệnh (chỉ không cung cấp bất cứ điều gì, và sau đó xử lý biến thể lành mạnh); cách tiếp cận quá tải toán tử có vẻ ... rất dài dòng (như ít nhất +3 dòng, so với kiểm tra null và nhiều dòng hơn nếu mã phức tạp hơn).
ngày

8

Như Scala đã được đề cập, Kotlin cũng đáng được đề cập. Trong các tham số chức năng của Kotlin cũng có thể có các giá trị mặc định và chúng thậm chí có thể tham chiếu đến các tham số khác:

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
    ...
}

Giống như Scala, Kotlin chạy trên JVM và có thể dễ dàng tích hợp vào các dự án Java hiện có.


6

Không.

Bạn có thể đạt được hành vi tương tự bằng cách vượt qua một Đối tượng có mặc định thông minh. Nhưng một lần nữa nó phụ thuộc vào trường hợp của bạn trong tầm tay.


5

Không. Nói chung, Java không có nhiều cú pháp cú pháp, vì họ đã cố gắng tạo ra một ngôn ngữ đơn giản.


26
Không hẳn. Sự thật cay đắng là đội đã có một lịch trình chặt chẽ và không có thời gian cho đường cú pháp. Tại sao khác constvà sẽ gotođược bảo lưu từ khóa mà không thực hiện? - Đặc biệt constlà một cái gì đó tôi nhớ cay đắng - finalkhông có gì thay thế và họ biết điều đó. - Và nếu bạn thực hiện ý thức quyết định không bao giờ thực hiện goto, bạn sẽ không cần phải bảo lưu từ khóa. - Và sau đó, Nhóm Java đã bị lừa bằng cách tạo Nhãn dựa trên breakcontinuemạnh như Pascal goto.
Martin

"Đơn giản, hướng đối tượng và quen thuộc" thực sự là một mục tiêu thiết kế - xem oracle.com/technetwork/java/intro-141325.html
mikera

1
tomjen nói: "Không. Nói chung Java không có nhiều cú pháp cú pháp, vì họ đã cố gắng tạo ra một ngôn ngữ đơn giản". Vì vậy, bạn đang nói rằng việc loại bỏ rất nhiều tính năng không cần thiết khỏi C ++ làm cho Java trở thành một ngôn ngữ đơn giản, sau đó cho tôi biết lý do tại sao Java có các phương thức matrixdic? Tại sao nó có varargs? Không cần thiết nếu bạn chỉ đơn giản có thể sử dụng một mảng các đối tượng thay vào đó, phải không? Vì vậy, varargs có thể được loại bỏ khỏi ngôn ngữ, vì nó không cần thiết. Điều này sẽ làm cho Java đơn giản hơn so với hiện tại. Tôi có đúng không Quá tải cũng có thể được loại bỏ, bởi vì bạn có tên vô hạn cho mỗi phương thức.

1
và đó là lý do tại sao chúng ta có mùa xuân và những thứ sử dụng ngôn ngữ đơn giản và biến bất kỳ dự án Java thực sự nào thành một cụm cú pháp và soạn thảo :-)
matanster

Buộc các nhà phát triển mã soạn sẵn và các cách giải quyết phức tạp không phải là cách hiểu của tôi về từ "dễ dàng". myFactor (a, b = false, c = 3), đó là điều tôi gọi là dễ dàng.
spyro

5

Thay vì sử dụng:

void parameterizedMethod(String param1, int param2) {
    this(param1, param2, false);
}

void parameterizedMethod(String param1, int param2, boolean param3) {
    //use all three parameters here
}

Bạn có thể sử dụng chức năng Tùy chọn của java bằng cách có một phương thức duy nhất:

void parameterizedMethod(String param1, int param2, @Nullable Boolean param3) {
    param3 = Optional.ofNullable(param3).orElse(false);
    //use all three parameters here
}

Sự khác biệt chính là bạn phải sử dụng các lớp trình bao bọc thay vì các kiểu Java nguyên thủy để cho phép nullnhập liệu. Booleanthay vì boolean, Integerthay vì intvà như vậy.


4

Nó không được hỗ trợ nhưng có một số tùy chọn như sử dụng mẫu đối tượng tham số với một số cú pháp đường:

public class Foo() {
    private static class ParameterObject {
        int param1 = 1;
        String param2 = "";
    }

    public static void main(String[] args) {
        new Foo().myMethod(new ParameterObject() {{ param1 = 10; param2 = "bar";}});
    }

    private void myMethod(ParameterObject po) {
    }
}

Trong mẫu này, chúng tôi xây dựng ParameterObjectvới các giá trị mặc định và ghi đè chúng trong phần khởi tạo thể hiện của lớp{ param1 = 10; param2 = "bar";}


3

Hãy thử giải pháp này:

public int getScore(int score, Integer... bonus)
{
    if(bonus.length > 0)
    {
        return score + bonus[0];
    }

    return score;
}

3

Bạn có thể sử dụng Trình tạo lệnh gọi phương thức Java để tự động tạo trình tạo với các giá trị mặc định.

Chỉ cần thêm @GenerateMethodInvocationBuilder vào lớp hoặc giao diện và @Default cho các tham số trong các phương thức mà bạn muốn các giá trị mặc định. Trình xây dựng sẽ được tạo tại thời điểm biên dịch, sử dụng các giá trị mặc định mà bạn đã chỉ định với các chú thích của mình.

@GenerateMethodInvocationBuilder
public class CarService {
 public CarService() {
 }

 public String getCarsByFilter(//
   @Default("Color.BLUE") Color color, //
   @Default("new ProductionYear(2001)") ProductionYear productionYear,//
   @Default("Tomas") String owner//
 ) {
  return "Filtering... " + color + productionYear + owner;
 }
}

Và sau đó bạn có thể gọi các phương thức.

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .invoke(instance);

Hoặc đặt bất kỳ giá trị mặc định nào khác.

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .withColor(Color.YELLOW)//
  .invoke(instance);

2

Một cách tiếp cận tương tự với https://stackoverflow.com/a/13864910/2323964 hoạt động trong Java 8 là sử dụng một giao diện với các getters mặc định. Điều này sẽ dài hơn khoảng trắng, nhưng có thể nhạo báng và thật tuyệt vời khi bạn có một loạt các trường hợp mà bạn thực sự muốn thu hút sự chú ý đến các tham số.

public class Foo() {
    public interface Parameters {
        String getRequired();
        default int getOptionalInt(){ return 23; }
        default String getOptionalString(){ return "Skidoo"; }
    }

    public Foo(Parameters parameters){
        //...
    }

    public static void baz() {
        final Foo foo = new Foo(new Person() {
            @Override public String getRequired(){ return "blahblahblah"; }
            @Override public int getOptionalInt(){ return 43; }
        });
    }
}

2

Bây giờ tôi đã dành khá nhiều thời gian để tìm ra cách sử dụng phương pháp này với các phương thức trả về giá trị và cho đến nay tôi chưa thấy bất kỳ ví dụ nào, tôi nghĩ rằng có thể hữu ích khi thêm điều này vào đây:

int foo(int a) {
    // do something with a
    return a;
}

int foo() {
    return foo(0); // here, 0 is a default value for a
}

1

Đây là cách tôi đã làm ... có lẽ nó không thuận tiện bằng việc có một 'đối số tùy chọn' chống lại tham số đã xác định của bạn, nhưng nó hoàn thành công việc:

public void postUserMessage(String s,boolean wipeClean)
{
    if(wipeClean)
    {
        userInformation.setText(s + "\n");
    }
    else
    {
        postUserMessage(s);
    }
}

public void postUserMessage(String s)
{
    userInformation.appendText(s + "\n");
}

Lưu ý rằng tôi có thể gọi cùng tên phương thức với chỉ một chuỗi hoặc tôi có thể gọi nó bằng một chuỗi và giá trị boolean. Trong trường hợp này, đặt lauClean thành true sẽ thay thế tất cả văn bản trong TextArea của tôi bằng chuỗi được cung cấp. Đặt lauClean thành false hoặc bỏ tất cả lại với nhau chỉ đơn giản là nối thêm văn bản được cung cấp vào TextArea.

Cũng lưu ý rằng tôi không lặp lại mã trong hai phương thức, tôi chỉ thêm chức năng để có thể đặt lại TextArea bằng cách tạo một phương thức mới có cùng tên chỉ với boolean được thêm vào.

Tôi thực sự nghĩ rằng điều này sạch hơn một chút so với việc Java cung cấp một 'đối số tùy chọn' cho các tham số của chúng tôi vì chúng tôi sẽ cần mã hóa các giá trị mặc định, v.v. Trong ví dụ này, tôi không cần phải lo lắng về điều đó. Vâng, tôi đã thêm một phương pháp khác vào lớp của mình, nhưng về lâu dài thì dễ đọc hơn trong quan điểm khiêm tốn của tôi.


1

KHÔNG, nhưng chúng tôi có sự thay thế ở dạng quá tải chức năng.

được gọi khi không có tham số nào được thông qua

void operation(){

int a = 0;
int b = 0;

} 

được gọi khi tham số "a" được thông qua

void operation(int a){

int b = 0;
//code

} 

được gọi khi tham số b đi qua

void operation(int a , int b){
//code
} 

1

Có một nửa tá vấn đề hoặc tốt hơn như thế này, cuối cùng, bạn đến mẫu nhà máy tĩnh ... xem API mật mã cho điều đó. Sắp xếp khó giải thích, nhưng hãy nghĩ về nó theo cách này: Nếu bạn có một hàm tạo, mặc định hoặc theo cách khác, cách duy nhất để truyền trạng thái ngoài các dấu ngoặc nhọn là có Boolean isValid; (cùng với null là giá trị mặc định v, hàm tạo không thành công) hoặc ném một ngoại lệ không bao giờ có thông tin khi lấy lại từ người dùng trường.

Code Correct bị nguyền rủa, tôi viết hàng ngàn constructor và làm những gì tôi cần. Tôi thấy việc sử dụng isValid khi xây dựng đối tượng - nói cách khác, các hàm tạo hai dòng - nhưng vì một số lý do, tôi đang chuyển sang mẫu nhà máy tĩnh. Tôi chỉ có vẻ như bạn có thể làm rất nhiều nếu bạn trong một cuộc gọi phương thức, vẫn có vấn đề đồng bộ hóa () nhưng mặc định có thể được 'thay thế' tốt hơn (an toàn hơn)

Tôi nghĩ rằng những gì chúng ta cần làm ở đây là giải quyết vấn đề null là giá trị mặc định vis-a-vis một cái gì đó String one = new String (""); như một biến thành viên, sau đó thực hiện kiểm tra null trước khi gán chuỗi được truyền cho hàm tạo.

Rất đáng chú ý số lượng khoa học máy tính thô, tầng bình lưu được thực hiện trong Java.

C ++ và như vậy có libs nhà cung cấp, vâng. Java có thể vượt qua chúng trên các máy chủ quy mô lớn do đó là một hộp công cụ lớn. Nghiên cứu các khối khởi tạo tĩnh, ở lại với chúng tôi.



0

Bạn có thể sử dụng như sau-

public void mop(Integer x) {
  // Define default values
        x = x == null ? 200 : x;
}
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.