Câu trả lời:
varargs có thể làm điều đó (theo một cách nào đó). Ngoài ra, tất cả các biến trong khai báo của phương thức phải được cung cấp. Nếu bạn muốn một biến là tùy chọn, bạn có thể nạp chồng phương thức bằng chữ ký không yêu cầu tham số.
private boolean defaultOptionalFlagValue = true;
public void doSomething(boolean optionalFlag) {
...
}
public void doSomething() {
doSomething(defaultOptionalFlagValue);
}
Có một số cách để mô phỏng các tham số tùy chọn trong Java:
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.
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.
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.
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.
Cập nhật: Java 8 bao gồm lớp java.util.Optional
ngoài hộp, do đó không cần sử dụng ổi vì lý do cụ thể này trong Java 8. Mặc dù vậy, tên phương thức hơi khác một chút.
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();
Bản đồ. Khi số lượng tham số quá lớn và đối với hầu hết 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 = (Integer)parameters.get("a");
}
if (parameters.containsKey("b")) {
//...
}
//...
}
foo(ImmutableMap.<String, Object>of(
"a", "a",
"b", 2,
"d", "value"));
Trong Java 9, cách tiếp cận này trở nên dễ dàng hơn:
@SuppressWarnings("unchecked")
static <T> T getParm(Map<String, Object> map, String key, T defaultValue)
{
return (map.containsKey(key)) ? (T) map.get(key) : defaultValue;
}
void foo(Map<String, Object> parameters) {
String a = getParm(parameters, "a", "");
int b = getParm(parameters, "b", 0);
// d = ...
}
foo(Map.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.
a
biến của bạn là String (cast là chính xác).
Có các tham số tùy chọn với Java 5.0. Chỉ cần khai báo chức năng của bạn như thế này:
public void doSomething(boolean... optionalFlag) {
//default to "false"
//boolean flag = (optionalFlag.length >= 1) ? optionalFlag[0] : false;
}
bạn có thể gọi với doSomething();
hoặc doSomething(true);
bây giờ.
doSomething() { doSomething(true); }
không có mảng để xử lý, không có sự mơ hồ
Bạn có thể sử dụng một cái gì đó như thế này:
public void addError(String path, String key, Object... params) {
}
Các params
biến là tùy chọn. Nó được coi là một mảng nullable của Object.
Kỳ lạ thay, tôi không thể tìm thấy bất cứ điều gì về điều này trong tài liệu, nhưng nó hoạt động!
Đây là "mới" trong Java 1.5 trở lên (không được hỗ trợ trong Java 1.4 trở về trước).
Tôi thấy người dùng bhoot đã đề cập đến điều này quá bên dưới.
Thật không may, Java không hỗ trợ các tham số mặc định trực tiếp.
Tuy nhiên, tôi đã viết một tập các chú thích JavaBean và một trong số chúng hỗ trợ các tham số mặc định như sau:
protected void process(
Processor processor,
String item,
@Default("Processor.Size.LARGE") Size size,
@Default("red") String color,
@Default("1") int quantity) {
processor.process(item, size, color, quantity);
}
public void report(@Default("Hello") String message) {
System.out.println("Message: " + message);
}
Bộ xử lý chú thích tạo ra quá tải phương thức để hỗ trợ chính xác điều này.
Xem http://code.google.com.vn/p/javadude/wiki/Annotations
Ví dụ đầy đủ tại http://code.google.com.vn/p/javadude/wiki/AnnotationsDefaultParameterExample
VarArss và quá tải đã được đề cập. Một tùy chọn khác là mẫu Builder, trông giống như thế này:
MyObject my = new MyObjectBuilder().setParam1(value)
.setParam3(otherValue)
.setParam6(thirdValue)
.build();
Mặc dù mẫu đó sẽ phù hợp nhất khi bạn cần các tham số tùy chọn trong hàm tạo.
Trong JDK> 1.5 bạn có thể sử dụng nó như thế này;
public class NewClass1 {
public static void main(String[] args) {
try {
someMethod(18); // Age : 18
someMethod(18, "John Doe"); // Age & Name : 18 & John Doe
} catch (Exception e) {
e.printStackTrace();
}
}
static void someMethod(int age, String... names) {
if (names.length > 0) {
if (names[0] != null) {
System.out.println("Age & Name : " + age + " & " + names[0]);
}
} else {
System.out.println("Age : " + age);
}
}
}
Bạn có thể làm điều bằng cách sử dụng phương thức nạp chồng như thế này.
public void load(String name){ }
public void load(String name,int age){}
Ngoài ra, bạn có thể sử dụng chú thích @Nullable
public void load(@Nullable String name,int age){}
chỉ cần truyền null làm tham số đầu tiên.
Nếu bạn đang chuyển biến cùng loại, bạn có thể sử dụng biến này
public void load(String name...){}
Quá tải là tốt, nhưng nếu có nhiều biến cần giá trị mặc định, bạn sẽ kết thúc bằng:
public void methodA(A arg1) { }
public void methodA( B arg2,) { }
public void methodA(C arg3) { }
public void methodA(A arg1, B arg2) { }
public void methodA(A arg1, C arg3) { }
public void methodA( B arg2, C arg3) { }
public void methodA(A arg1, B arg2, C arg3) { }
Vì vậy, tôi sẽ đề nghị sử dụng Đối số biến do Java cung cấp. Đây là một liên kết để giải thích.
Bạn có thể sử dụng một lớp hoạt động giống như một trình xây dựng để chứa các giá trị tùy chọn của bạn như thế này.
public class Options {
private String someString = "default value";
private int someInt= 0;
public Options setSomeString(String someString) {
this.someString = someString;
return this;
}
public Options setSomeInt(int someInt) {
this.someInt = someInt;
return this;
}
}
public static void foo(Consumer<Options> consumer) {
Options options = new Options();
consumer.accept(options);
System.out.println("someString = " + options.someString + ", someInt = " + options.someInt);
}
Sử dụng như
foo(o -> o.setSomeString("something").setSomeInt(5));
Đầu ra là
someString = something, someInt = 5
Để bỏ qua tất cả các giá trị tùy chọn bạn phải gọi nó như thế nào foo(o -> {});
hoặc nếu bạn thích, bạn có thể tạo một foo()
phương thức thứ hai không lấy các tham số tùy chọn.
Sử dụng phương pháp này, bạn có thể chỉ định các giá trị tùy chọn theo bất kỳ thứ tự nào mà không có bất kỳ sự mơ hồ nào. Bạn cũng có thể có các tham số của các lớp khác nhau không giống như varargs. Cách tiếp cận này sẽ còn tốt hơn nữa nếu bạn có thể sử dụng các chú thích và tạo mã để tạo lớp Tùy chọn.
Java hiện hỗ trợ các tùy chọn trong 1.8, tôi bị mắc kẹt với lập trình trên Android vì vậy tôi đang sử dụng null cho đến khi tôi có thể cấu trúc lại mã để sử dụng các loại tùy chọn.
Object canBeNull() {
if (blah) {
return new Object();
} else {
return null;
}
}
Object optionalObject = canBeNull();
if (optionalObject != null) {
// new object returned
} else {
// no new object returned
}
Đối số mặc định không thể được sử dụng trong Java. Trong C #, C ++ và Python, chúng ta có thể sử dụng chúng ..
Trong Java, chúng ta phải sử dụng 2 phương thức (hàm) thay vì một phương thức với các tham số mặc định.
Thí dụ:
Stash(int size);
Stash(int size, int initQuantity);
Đây là một câu hỏi cũ có thể ngay cả trước khi loại Tùy chọn thực tế được giới thiệu nhưng ngày nay bạn có thể cân nhắc một số điều: - sử dụng phương thức nạp chồng - sử dụng Loại tùy chọn có lợi thế là tránh truyền NULL xung quanh Loại tùy chọn được giới thiệu trong Java 8 trước khi nó thường được sử dụng từ lib của bên thứ ba như Guava của Google. Sử dụng tùy chọn làm tham số / đối số có thể được coi là sử dụng quá mức vì mục đích chính là sử dụng nó làm thời gian trả về.
Tham chiếu: https://itcodehub.blogspot.com/2019/06/USE-optional-type-in-java.html
Chúng ta có thể tạo tham số tùy chọn bằng cách nạp chồng Phương thức hoặc Sử dụng DataType ...
| * | Phương thức nạp chồng:
RetDataType NameFnc(int NamePsgVar)
{
// |* Code Todo *|
return RetVar;
}
RetDataType NameFnc(String NamePsgVar)
{
// |* Code Todo *|
return RetVar;
}
RetDataType NameFnc(int NamePsgVar1, String NamePsgVar2)
{
// |* Code Todo *|
return RetVar;
}
Cách dễ nhất là
| * | DataType ... có thể là tham số tùy chọn
RetDataType NameFnc(int NamePsgVar, String... stringOpnPsgVar)
{
if(stringOpnPsgVar.length == 0) stringOpnPsgVar = DefaultValue;
// |* Code Todo *|
return RetVar;
}
RetDtaTyp
... nghiêm túc? Là RetDataType
quá khó để loại ra?
Nếu bạn đang dự định sử dụng một giao diện có nhiều tham số , người ta có thể sử dụng mẫu cấu trúc sau và áp dụng hoặc ghi đè - một phương pháp dựa trên yêu cầu của bạn .
public abstract class Invoker<T> {
public T apply() {
return apply(null);
}
public abstract T apply(Object... params);
}
Nếu đó là điểm cuối API, một cách trang nhã là sử dụng chú thích "Mùa xuân":
@GetMapping("/api/foos")
@ResponseBody
public String getFoos(@RequestParam(required = false, defaultValue = "hello") String id) {
return innerFunc(id);
}
Lưu ý trong trường hợp này là InternalFunc sẽ yêu cầu biến và vì nó không phải là điểm cuối api, nên không thể sử dụng chú thích Mùa xuân này để làm cho nó tùy chọn. Tham khảo: https://www.baeldung.com/spring-request-param