[java] Java가 기본 매개 변수 값을 지원합니까?

다음과 같은 구조를 가진 일부 Java 코드를 발견했습니다.

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

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

C ++에서 매개 변수에 기본값을 할당 할 수 있다는 것을 알고 있습니다. 예를 들면 다음과 같습니다.

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

Java가 이런 종류의 구문을 지원합니까? 이 두 단계 구문이 바람직한 이유가 있습니까?



답변

아니오, 발견 한 구조는 Java가 Java를 처리하는 방식입니다 (즉, 기본 매개 변수 대신 오버로드 사용).

생성자 가 오버로드가 복잡 해지는 경우 효과적인 Java : 프로그래밍 언어 안내서의 항목 1 팁 (생성자 대신 정적 팩토리 메소드 고려)을 참조하십시오. 다른 방법의 경우 일부 사례의 이름을 바꾸거나 매개 변수 객체를 사용하면 도움이 될 수 있습니다. 이것은 차별화가 어려운 복잡성이 충분할 때입니다. 명확한 경우는 숫자와 유형뿐만 아니라 매개 변수의 순서를 사용하여 차별화해야하는 경우입니다.


답변

아니요, 그러나이 스택 오버플로 답변에 설명 된대로 빌더 패턴을 사용할 수 있습니다 .

링크 된 답변에 설명 된 것처럼 빌더 패턴을 사용하면 다음과 같은 코드를 작성할 수 있습니다

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

일부 필드는 기본값을 가질 수 있거나 그렇지 않은 경우 선택 사항입니다.


답변

Java에서 기본 매개 변수를 시뮬레이션하는 몇 가지 방법이 있습니다.

  1. 메서드 오버로딩

    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");

    이 방법의 한계 중 하나는 동일한 유형의 두 개의 선택적 매개 변수가 있고 작동하지 않을 경우 작동하지 않는다는 것입니다.

  2. Varargs.

    a) 모든 선택적 매개 변수는 동일한 유형입니다.

    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) 선택적 매개 변수의 유형은 다를 수 있습니다.

    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");

    이 방법의 주요 단점은 선택적 매개 변수가 다른 유형 인 경우 정적 유형 검사를 잃는다는 것입니다. 또한 각 매개 변수의 의미가 다르면이를 구별 할 방법이 필요합니다.

  3. 널. 이전 접근법의 한계를 해결하기 위해 널값을 허용 한 후 메소드 본문에서 각 매개 변수를 분석 할 수 있습니다.

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

    이제 모든 인수 값을 제공해야하지만 기본 값은 null 일 수 있습니다.

  4. 선택적 수업. 이 방법은 null과 비슷하지만 기본값이있는 매개 변수에 Java 8 Optional 클래스를 사용합니다.

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

    선택 사항은 호출자에게 메소드 계약을 명시 적으로 표시하지만, 그러한 서명이 너무 자세 할 수 있습니다.

  5. 빌더 패턴. 빌더 패턴은 생성자에 사용되며 별도의 Builder 클래스를 도입하여 구현됩니다.

     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. 지도. 매개 변수 수가 너무 많고 대부분의 기본값이 일반적으로 사용되는 경우 메소드 인수를 해당 이름 / 값의 맵으로 전달할 수 있습니다.

    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")); 

이러한 방법 중 하나를 결합하여 원하는 결과를 얻을 수 있습니다.


답변

안타깝게도


답변

불행히도, 그렇습니다.

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

Java 1.5에서 다음과 같이 작성할 수 있습니다.

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

그러나 컴파일러가 컴퓨터를 생성하는 것에 대한 느낌에 의존 해야하는지 여부

new Boolean[]{}

각 통화마다.

여러 기본 매개 변수의 경우 :

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

Java 1.5에서 다음과 같이 작성할 수 있습니다.

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;
}

이는 C ++ 구문과 일치하며 매개 변수 목록 끝에 기본 매개 변수 만 허용합니다.

구문 외에도 전달 된 기본 매개 변수에 대한 런타임 유형 검사와 컴파일 중 C ++ 유형 검사에 차이가 있습니다.


답변

아니요, 그러나 매우 쉽게 에뮬레이션 할 수 있습니다. C ++의 내용 :

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

Java에서는 오버로드 된 함수가됩니다.

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);
}

이전에는 기본 매개 변수로 인해 함수 오버로드가 모호한 경우가 발생했습니다. 그것은 사실이 아닙니다. C ++의 경우에서 볼 수 있습니다. 예, 모호한 경우를 만들 수 있지만 이러한 문제는 쉽게 처리 할 수 ​​있습니다. C ++처럼 훨씬 간단한 언어를 원했기 때문에 Java로 개발되지 않았을 것입니다. 그러나 대부분의 사람들은 단순성 때문에 Java를 사용하지 않는다고 생각합니다.


답변

이 작업은 Scala에서 수행되며, JVM에서 실행되며 Java 프로그램과 호환됩니다.
http://www.scala-lang.org/

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