메서드를 정적으로 가져 오기위한 좋은 사용 사례는 무엇입니까?


137

방금 정적 메소드 가져 오기가 좋지 않다는 리뷰 의견이 있습니다. 정적 가져 오기는 주로 정적 메소드가있는 DA 클래스의 메소드입니다. 따라서 비즈니스 논리의 중간에 현재 클래스에 속하는 것처럼 보이는 da 활동이있었습니다.

import static some.package.DA.*;
class BusinessObject {
  void someMethod() {
    ....
    save(this);
  }
} 

리뷰어는 코드를 바꾸는 데 열중하지 않았지만 그렇게하지는 않았지만 나는 그에게 동의합니다. 정적 가져 오기가 아닌 이유 중 하나는 메소드가 정의 된 위치가 혼란스럽고 현재 클래스가 아니고 수퍼 클래스가 아니기 때문에 정의를 식별하기에는 너무 시간이 걸리기 때문입니다 (웹 기반 검토 시스템에는 클릭 할 수 없음) IDE와 같은 링크 :-) 나는 이것이 중요하다고 생각하지 않습니다. 정적 가져 오기는 여전히 새롭고 곧 우리는 그것들을 찾는 데 익숙해 질 것입니다.

그러나 내가 동의하는 다른 이유는 규정되지 않은 메소드 호출이 현재 객체에 속하는 것으로 보이므로 컨텍스트를 뛰어 넘지 않아야하기 때문입니다. 그러나 그것이 실제로 속해 있다면, 그 슈퍼 클래스를 확장하는 것이 합리적입니다.

그래서, 때 않습니다 그것은 정적 수입 방법에 대한 이해가? 언제 했어요? 정규화되지 않은 전화 모양을 좋아했습니까?

편집 : 대중적인 의견은 아무도 정적 가져 오기 메소드를 현재 클래스의 메소드로 혼동하지 않을 것입니다. 예를 들어 java.lang.Math 및 java.awt.Color의 메소드입니다. 그러나 abs와 getAlpha가 모호하지 않으면 readEmployee가 왜 그런지 알 수 없습니다. 많은 프로그래밍 선택에서와 마찬가지로, 나는 이것 또한 개인적인 선호 사항이라고 생각합니다.

답변 해 주셔서 감사합니다. 질문을 닫습니다.


2
정적 가져 오기 사용법은 다음과 같습니다. ibm.com/developerworks/library/j-ft18
intrepidis

1
@ mr5 구문은 import static, 기능은 다음과 같습니다static import
Miserable Variable

답변:


150

이 기능을 릴리스했을 때의 Sun 안내서에서 가져온 것입니다 (원본에서 강조 표시).

정적 가져 오기를 언제 사용해야합니까? 매우 드물게! 상수의 로컬 사본을 선언하거나 상속을 남용하려는 유혹이있는 경우에만 사용하십시오 (Constant Interface Antipattern). ... 정적 가져 오기 기능을 과도하게 사용하면 프로그램을 읽을 수없고 유지 관리 할 수 ​​없어서 가져 오는 모든 정적 멤버로 네임 스페이스를 오염시킬 수 있습니다. 코드를 작성한 후 몇 개월이 지난 후에도 코드 멤버는 정적 멤버의 클래스를 알 수 없습니다. 클래스에서 모든 정적 멤버를 가져 오는 것은 특히 가독성에 해로울 수 있습니다. 하나 또는 두 개의 멤버 만 필요한 경우 개별적으로 가져 오십시오.

( https://docs.oracle.com/javase/8/docs/technotes/guides/language/static-import.html )

구체적으로 설명하고 싶은 두 부분이 있습니다.

  • "상속을 남용하려는"유혹이있을 때만 정적 가져 오기를 사용하십시오 . 이 경우 BusinessObject를 갖고 싶은 유혹을 extend some.package.DA받았습니까? 그렇다면 정적 가져 오기가이를보다 깔끔하게 처리 할 수 ​​있습니다. 확장을 꿈꿔 본 적이 없다면 some.package.DA정적 가져 오기를 제대로 사용 하지 않는 것일 수 있습니다. 입력 할 때 문자를 몇 개만 저장하는 데 사용하지 마십시오.
  • 개별 회원을 가져옵니다. import static some.package.DA.save대신 말하십시오 DA.*. 이렇게하면이 가져온 방법의 출처를 훨씬 쉽게 찾을 수 있습니다.

개인적으로, 나는이 언어 기능을 사용하지 않은 매우 결코 방법으로 만 상수 또는 열거 거의 항상 거의합니다. 절충은 거의 가치가 없습니다.


9
동의했다. 정적 가져 오기 veeery를 사용하여 실제로 코드를 훨씬 쉽게 따라갈 수있는 경우가있었습니다.
Neil Coffey

65

정적 가져 오기에 대한 또 다른 합리적인 용도는 JUnit 4를 사용하는 것입니다. 이전 버전의 JUnit 메소드 에서는 테스트 클래스 확장 이후 assertEquals와 같고 fail상속되었습니다 junit.framework.TestCase.

// old way
import junit.framework.TestCase;

public class MyTestClass extends TestCase {
    public void myMethodTest() {
        assertEquals("foo", "bar");
    }
}

JUnit 4에서 테스트 클래스는 더 이상 확장 할 필요가 없으며 TestCase대신 주석을 사용할 수 있습니다. 그런 다음 다음에서 assert 메소드를 정적으로 가져올 수 있습니다 org.junit.Assert.

// new way
import static org.junit.Assert.assertEquals;

public class MyTestClass {
    @Test public void myMethodTest() {
        assertEquals("foo", "bar");
        // instead of
        Assert.assertEquals("foo", "bar");
    }
}

JUnit은 이것을 사용하여 문서화 합니다.


4
동의합니다. 테스트 사례를 단순화하는 것은 의도가 잘못 이해되지 않는 곳입니다.
Bill Michell

6
우리는 프로젝트에서 이것을 가지고 있었고 실제로 assert ()를 사용하는 사람들과 문제가 있었고 Assert 패키지의 정적 가져 오기에서 비롯되었다고 잘못 생각했습니다. 이 문제를 발견하면 테스트에서 코드 기반의 빠른 스캔으로 약 30 개의 인스턴스가 테스트에서 발견되었는데, 이는 테스트를 실행할 때 DEBUG 플래그가 설정되지 않았기 때문에 테스트 프레임 워크가 실행될 때 30 개의 어설 션이 실행되지 않았 음을 의미합니다.
Chris Williams

27

항목 19 의 끝 부분 인 Effective Java, Second Edition 에서는 유틸리티 클래스의 상수를 많이 사용하는 경우 정적 가져 오기를 사용할 수 있습니다 . 이 원칙은 상수와 메소드의 정적 가져 오기에 적용된다고 생각합니다.

import static com.example.UtilityClassWithFrequentlyUsedMethods.myMethod;

public class MyClass {
    public void doSomething() {
        int foo= UtilityClassWithFrequentlyUsedMethods.myMethod();
        // can be written less verbosely as
        int bar = myMethod();
    }
}

이것은 장단점이 있습니다. 메소드가 정의 된 위치에 대한 즉각적인 정보가 손실되는 대신 코드를 좀 더 읽기 쉽게 만듭니다. 그러나 좋은 IDE를 사용하면 정의로 이동할 수 있으므로 큰 문제는 아닙니다.

가져온 파일의 항목을 여러 번 사용하는 경우에만이 방법을 조금만 사용해야합니다.

편집 : 이 질문에서 언급 한 것처럼 메소드에 더 구체적으로 업데이트되었습니다. 가져 오는 내용 (상수 또는 방법)에 관계없이 원칙이 적용됩니다.


1
내 질문은 필드가 아닌 정적 가져 오기 방법 에 관한 것 입니다.
비참한 변수

7
아마도 UtilityClassWithFrequentlyUsedMethods단축해야합니다.
Steve Kuo


@ Rob-Hruska 정적 가져 오기 메소드 또는 필드를 자주 사용하려는 경우 새 메소드 또는 필드로 랩핑 할 수 없었습니까? 정적으로 가져올 수 없습니까? 와 같은 : double myPI = Math.PI;그리고 나는 myPI대신에 계속 참조 할 수 있습니다 Math.PI.
Abdul

@ Abdul-그래, 당신은 할 수 있습니다.
Rob Hruska

14

나는 그것들이 가독성 관점에서 문제가 될 수 있으며 드물게 사용해야한다는 데 동의합니다. 그러나 일반적인 정적 방법을 사용하면 실제로 가독성을 높일 수 있습니다. 예를 들어, JUnit 테스트 클래스에서 메소드 assertEquals는 어디에서 왔는지 분명합니다. 의 메소드와 유사합니다 java.lang.Math.


5
그리고 Math.round (d)와 round (d)를 볼 때 무엇이 ​​나쁜가요?
Steve Kuo

5
@SteveKuo-수학자가 수식을 조작 할 때 한 글자로 된 변수 이름을 사용하는 것과 같은 이유로 더 긴 이름이 전체 문장의 가독성을 방해하는 경우가 있습니다. 여러 삼각 함수가 포함 된 공식을 고려하십시오. 쉽게 파악할 수있는 수학 공식 : sin x cos y + cos x sin y. Java에서는 다음과 같이 Math.sin(x) * Math.cos(y) + Math.cos(x) * Math.sin(y)됩니다. 읽기 끔찍하다.
ToolmakerSteve

@ToolmakerSteve, using그래서 C ++에서 지시문을 많이 놓친 이유 는 로컬 일 수 있습니다 .
Franklin Yu

11

정적 가져 오기는 Arraysand 같은 utils 클래스를 사용할 때 중복 클래스 이름을 제거하는 데 실제로 유용하다고 생각합니다 Assertions.

왜 그런지 모르지만 로스 는 그가 언급 한 문서 에서 이것을 언급 한 마지막 문장을 생략했다 .

적절하게 사용하면 정적 가져 오기를 사용하면 클래스 이름이 반복되는 상용구를 제거하여 프로그램을 더 읽기 쉽게 만들 수 있습니다.

이 블로그에서 기본적으로 복사 : https://medium.com/alphadev-thoughts/static-imports-are-great-but-underused-e805ba9b279f

예를 들어 :

테스트의 주장

이것은 우리 모두가 동의하는 가장 명백한 경우입니다

Assertions.assertThat(1).isEqualTo(2);

// Use static import instead
assertThat(1).isEqualTo(2);

유틸리티 클래스와 열거 형

utils 클래스를 사용하면 코드를 쉽게 읽을 수 있도록 클래스 이름을 제거 할 수있는 경우가 많습니다

List<Integer> numbers = Arrays.asList(1, 2, 3);

// asList method name is enough information
List<Integer> numbers = asList(1, 2, 3);

java.time 패키지에는 사용해야 할 몇 가지 경우가 있습니다.

// Get next Friday from now, quite annoying to read
LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.FRIDAY));

// More concise and easier to read
LocalDate.now().with(next(FRIDAY));

사용하지 않을 때의 예

// Ok this is an Optional
Optional.of("hello world");

// I have no idea what this is 
of("hello world");

10

칼라에 많이 사용하고 있습니다.

static import java.awt.Color.*;

색상이 다른 것과 혼동 될 가능성은 거의 없습니다.


1
그것은 내가 본 Juse / Hamcrest / TestNG와 다른 최고의 사용 사례 중 하나입니다.
kevinarpe 2016 년

3

Java와 함께 OpenGL을 사용할 때 정적 가져 오기 를 사용 하는 것이 좋습니다. 이는 "유틸리티 클래스의 상수를 많이 사용"하는 경우입니다. 범주의

그것을 고려하십시오

import static android.opengl.GLES20.*;

원본 C 코드를 이식하고 다음과 같이 읽을 수있는 것을 작성할 수 있습니다.

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(samplerUniform, 0);
glBindBuffer(GL_ARRAY_BUFFER, vtxBuffer);
glVertexAttribPointer(vtxAttrib, 3, GL_FLOAT, false, 0, 0);

그 보편적 인 못생긴 것 대신 :

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(samplerUniform, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vtxBuffer);
GLES20.glVertexAttribPointer(vtxAttrib, 3, GLES20.GL_FLOAT, false, 0, 0);

2

정적 가져 오기는 방금 언급 한 문제로 인해 내가 사용한 적이없고 사용하지 않을 Java의 유일한 "새로운"기능입니다.


고마워 Bombe. 글쎄, 나는 그들이 많은 정적 결승을 포함하는 확장하고 인터페이스해야한다는 것이 더 잘 이해된다고 생각합니다.
Miserable Variable

2

수학 무거운 코드를 C / C ++에서 java로 이식 할 때 'import static java.lang.Math. *'를 사용합니다. 수학 방법은 1에서 1로 매핑되며 클래스 이름 자격 없이도 이식 된 코드를 쉽게 비교할 수 있습니다.


2

유틸리티 클래스를 사용할 때 이것이 매우 편리하다는 것을 알았습니다.

예를 들어, 다음을 사용하는 대신 : if(CollectionUtils.isNotEmpty(col))

대신에 할 수 있습니다 :

import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
if(isNotEmpty(col))

내 코드에서이 유틸리티를 여러 번 사용할 때 코드 가독성을 높이는 IMO


2

단위 테스트에 대한 이야기 ​​: 대부분의 사람들은 모의 프레임 워크가 제공 하는 다양한 정적 메소드 ( 예 : when()또는)에 정적 가져 오기를 사용합니다 verify().

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

물론 하나만 사용하는 경우 다음과 assertThat()같이 필요한 hamcrest 매처를 정적으로 가져 오는 것이 편리합니다.

import static org.hamcrest.Matchers.*;

1

특히 가져온 메서드가 많이 호출되고 로컬 메서드와 가져온 메서드의 구분이 분명한 경우에, 언어를 줄이는 데 유용합니다.

한 가지 예 : java.lang.Math에 대한 여러 참조를 포함하는 코드

다른 : 클래스 이름을 모든 참조 앞에 추가하면 빌드중인 구조가 숨겨지는 XML 빌더 클래스


1

gettext 스타일에서 정적 가져 오기가 NLS에 깔끔하다고 생각합니다.

import static mypackage.TranslatorUtil._;

//...
System.out.println(_("Hello world."));

둘 다 문자열을 추출해야하는 문자열로 표시하고 문자열을 번역으로 바꾸는 쉽고 깨끗한 방법을 제공합니다.


1

IMO 정적 가져 오기는 매우 유용한 기능입니다. 정적 임포트에 대한 의존도가 높으면 코드를 읽을 수없고 정적 메소드 또는 속성이 속하는 클래스를 이해하기 어렵다는 것이 절대적으로 사실입니다. 그러나 내 경험상 특히 Util정적 메서드와 속성을 제공하는 클래스를 디자인 할 때 유용한 기능이됩니다 . 정적 가져 오기를 제공 할 때마다 발생하는 모호성은 코드 표준을 설정하여 피할 수 있습니다. 회사 내 경험에서이 접근 방식은 수용 가능하며 코드를 더 깨끗하고 이해하기 쉽게 만듭니다. 바람직하게는을 삽입합니다 . 분명히이 접근법은 Java의 명명 표준을 위반하지만 코드를 명확하게 제공합니다. 예를 들어 AngleUtils 클래스가있는 경우 :_ 문자를 정적 메소드와 정적 속성 앞에 합니다 (어떻게 C에서 채택)

public class AngleUtils {

    public static final float _ZERO = 0.0f;
    public static final float _PI   = 3.14f;

    public static float _angleDiff(float angle1, float angle2){

    }

    public static float _addAngle(float target, float dest){

    }
}

이 경우 정적 가져 오기는 명확성을 제공하고 코드 구조는 나에게 더 우아해 보입니다.

import static AngleUtils.*;

public class TestClass{

    public void testAngles(){

        float initialAngle = _ZERO;
        float angle1, angle2;
        _addAngle(angle1, angle2);
    }
}

즉시 누군가가 어떤 메소드 또는 속성을 정적 가져 오기에서 가져 왔는지 알 수 있으며 해당 메소드 또는 속성이 속한 클래스의 정보를 숨 깁니다. 모듈의 일부인 클래스에 정적 가져 오기를 사용하고 정적 및 비 정적 메소드를 제공하는 것이 좋습니다.이 경우 어떤 정적 클래스가 특정 정적 기능을 제공하는지 아는 것이 중요합니다.


이름을 다시 제안 해 주셔서 감사합니다. 전면 밑줄 인 BTW는 전통적으로 일부 환경에서 개인 방법 / 분야의 이름을 지정하는 데 사용됩니다. 나는 다음과 같은 수정 된 규칙, 고려하고 H_A로부터 수입 Helper내가, 또는이 유틸리티 클래스 C_에 대한 Common, 또는 U_를 들어 Utility. 또는 널리 사용되는 클래스에 하나 또는 두 개의 문자 클래스 이름을 사용하는 것을 고려했지만 때로는 로컬 이름과 충돌 할 수 있다는 우려가있었습니다.
ToolmakerSteve

-1

다음과 같은 경우에 사용해야합니다.

  • switch열거 형 값을 가진 명령문 을 사용하려고 합니다
  • 코드를 이해하기 어렵게 만들고 싶습니다

9
사실이 아닙니다. (1) 열거 상수를 정적 가져 오기없이 완벽하게 잘 사용할 수 있습니다. (2) JUnit Assert 클래스 메소드의 정적 가져 오기는 종소리로 분명합니다. "assertTrue (...)"는 "Assert.assertTrue (...)"와 마찬가지로 읽을 수 있습니다.
Alan Krueger

5
500 개의 라인 클래스에 5 개의 정적 가져 오기가있는 경우 메소드의 출처를 파악하기가 매우 어렵습니다.
davetron5000

4
코드를 이해하기 어려운 경우 +1 :)
Miserable Variable

-5

나는 가능할 때마다 그것들을 사용합니다. 잊어 버린 경우 알려주도록 IntelliJ를 설정했습니다. 나는 그것이 정규화 된 패키지 이름보다 훨씬 깨끗해 보인다고 생각합니다.


13
당신은 정기적 인 수입을 생각하고 있습니다. 정적 가져 오기를 사용하면 클래스 이름으로 규정하지 않고 클래스 멤버를 참조 할 수 있습니다 (예 : static import java.lang.system.out; out.println ( "foo"); // System.out.println ( "foo") 대신
sk.

이제 이것은 정적 임포트에 대한 아주 좋은 설명입니다 ... 너무 나쁩니다 +1 할 수 없습니다
Eldelshell
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.