조건부 인 경우 set.add ()의 부울 반환?


15

set 클래스의 add 연산자는 추가 할 요소가없는 경우 true를 반환하고 그렇지 않으면 false를 반환합니다. 기록하고있다

if (set.add(entry)) {
    //do some more stuff
}

깨끗한 코드 작성 측면에서 좋은 스타일로 간주됩니까? 한 번에 두 가지 일을했기 때문에 궁금합니다. 1) 요소 추가 및 2) 요소 존재 여부 확인


6
표준에 대해 이야기 하고 있습니다. 요소가 아직 없을 때 java.util.Settrue를 반환합니다 add.
user2357112는

1
: 나는 보통 반대 테스트 고려할 것if (!set.add(entry)) {// entry already present, possibly a case you want to handle}
njzk2

한 번에 두 가지 일을하는 데 문제가 있습니까?
user207421

@ user2357112 예, 그렇습니다.
Andreas Braun

답변:


19

그렇습니다.

오퍼레이션이 부울 값을 리턴하도록하는 일반적인 지점은이를 사용하여 의사 결정을 수행 할 수 있다는 것 if입니다. 유일한 다른 방법이 잠재 변수에 반환 값을 저장하고 다음 즉시에 다시 사용할 것 실현할 수 if있는 방법 그냥 바보 확실히 쓰기에 바람직하지 않다 if(operation()) { ... }. 그냥 가서 그렇게하세요, 우리는 당신을 판단하지 않을 것입니다.


답변 주셔서 감사합니다. @Niels vanReijmersdal이 대답을 지적하면 명령과 쿼리 분리가 중단되지 않습니까? 그게 중요하다고 생각하지 않습니까?
Andreas Braun

4
@AndreasBraun 개인적으로 나는 명령 쿼리 분리가 바보라고 생각합니다. 하나의 메소드가 조치를 수행하고 해당 조치와 관련된 값을 리턴하는 것이 종종 논리적입니다. 두 개 사이를 인위적으로 분리하면 코드가 불필요하게 장황하게됩니다.

1
@ dan1111 : 참으로. 또한, "명령과 쿼리 분리"는 "체크 앤 액트 (check then act)"및 유사한 안티 패턴으로 이어지며, 이는 다중 스레드 컨텍스트에서 깨질 수 있습니다. 세계의 다른 지역이 동시에 강력하고 효율적인 SMP 솔루션을 위해 원자 융합 작업을 구축하려고 할 때 그러한 분리를 광고하는 것은 다소 이상합니다.
Holger

2
@ Jörg W Mittag : 759 페이지 무엇? 원자 동작은 본질적으로 "체크 앤 액트 (check then act)"안티 패턴에 대해 면역성이 있기 때문에, 무엇을 찾아야하는지에 대한 "전체 장"을 읽기 위해 그것을 분할하는 것, 구조 스레드를 안전하게 만드는 방법 다시. 실제 주장의 이름을 밝히지 않았기 때문에“그 주장에 대한 구체적인 반대 의견”은 없습니다.
Holger

1
@ Jörg W Mittag : 글쎄, 나는이 페이지의 대답에 대해 이야기하고 있는데 Set.add, 대안을 명명하지 않고 단일 작업으로 사용 하는 것을 권장하지 않습니다 . 의도 된 작업이 단일 요소를 추가하고 추가되었는지 여부를 확인하는 경우 여전히 이점없이 작업을 복잡하게하는보다 강력한 대안이 필요하지 않습니다. Set.add700 페이지가 넘는 페이지를 먼저 공부하지 않고 사용할 수있는 내장 JRE 방법이라는 것을 알고 있기를 바랍니다 .
Holger

12

유지 보수 담당자가 이미 반환 값의 의미를 알고 있거나 찾아야하기 때문에 가능한 한 깨끗하지 않다고 말하고 싶습니다. 이미 존재하거나 존재하지 않았거나 값이 성공적으로 삽입되었다는 의미입니까? 많이 사용하지 않으면 알 수 없으며, 사용하더라도 훨씬 더 정신적 인 부담입니다.

나는 다음을 선호한다 :

boolean added = set.add(entry);

if (added) {
    //do some more stuff
}

예, 조금 더 장황하지만 컴파일러는 거의 동일한 바이트 코드를 생성해야하며 몇 년 동안 Java 세트를 사용하지 않은 사람들조차도 아무것도 보지 않고도 논리를 따를 수 있습니다.



9
메소드를 찾는 것은 사용되는 범위 밖에서 선언 된 중복 변수에 대한 원래 개발자의 의도를 이해하려는 것보다 부담이 적습니다. 모든 최신 Java IDE에서 개발자는 마우스 포인터를 메소드 위에 놓고 즉시 문서에 액세스 할 수 있습니다. 좋은 개발자는 익숙하지 않은 API로 작업 할 때이를 지속적으로 수행합니다.
Kevin Krumwiede

9
나는 두 번째 @Holger. 당신이 모르는 경우에 Set.add, 당신은 경험이없고 당신 그것을 배우고 더 경험이 되려면이 방법들을 찾아야합니다.
Reinstate Monica

7
notAlreadyPresent최고의 표현이 아닙니다. 나는을 사용 added하고 독자가 값이 세트에 추가되지 않는 이유를 알기를 기대합니다.
njzk2

3
@JustinTime : 주석을 사용하여 코드의 기능을 설명하는 것은 나쁜 습관으로 널리 간주됩니다. 코드는 자체 설명해야합니다. 코드 검토에서 귀하의 예제를 허용되지 않는 것으로 표시합니다.
BlueRaja-대니 Pflughoeft

8

참이 성공을 의미한다면, 그것은 분명하고 명확한 코드입니다.

함수 나 메소드가 성공하면 true (또는 true로 평가되는 것)를 반환한다는 광범위한 규칙이 있습니다. 귀하의 코드가 그에 따르는 한, 조건에 메소드를 넣는 것이 좋습니다.

이 같은 코드는 필자의 관점에서 불필요하게 어수선합니다.

boolean frobulate_succeeded = thing.frobulate();

if (frobulate_succeeded) {
    ...
}

자신을 반복하는 것처럼 느껴집니다.

그러나 반환 값의 의미에 대해서는 문제가 모호합니다. "추가 된 요소가 이미 존재하는지 여부를 나타내는 부울"이라고 말하면 true는 요소가 존재하고 추가가 발생하지 않았 음을 의미 할 수 있습니다. 이 경우 메소드의 리턴 동작을보다 일반적인 것으로 변경하는 것이 이상적입니다. 이것이 가능하지 않은 경우 코드에 반환 결과에 명확하게 레이블을 지정할 수있는 추가 중간 변수를 추가합니다 (다른 사람들이 제안한대로).


세트에 아이템을 추가 할 때 성공이란 무엇입니까? 예외를 던지지 않으면 성공을 의미합니다. 참과 거짓은이 맥락에서 더 구체적인 것을 의미합니다.
Reinstate Monica

@ Solomonoff'sSecret이 경우 예외는 세트가 요소 추가를 거부 false했음을 의미하고, 요소가 이미 포함되어 추가되지 않았 음을 true의미하고, 요소가 아직 포함되지 않았 음을 의미합니다. 으로는 add()세트가 이미 그것을 포함하지 않은 경우 세트에 요소를 추가 true요소가 성공적으로 세트에 추가 된, 따라서 수단을.
저스틴 타임-복원 모니카

@JustinTime 두 가지 경우에 자신의 가치 판단을 추가하고 있습니다. 다른 해석은 성공은 메소드가 리턴 할 때 항목이 세트에 있다는 것입니다. 항목이 이미 세트에 있으면 add아무 것도하지 않아도 성공합니다. 아이템이 아직 세트에 없으면 아이템을 세트 add에 추가하여 성공합니다. 어떤 해석이 올바른지는 임의적입니다. 성공에 대한 덜 자의적인 정의는 언어에서 나온 것입니다. 정상적으로 반환되면 메소드가 성공합니다.
Reinstate Monica

1
성공의 최소 임의 정의는 메소드가 수행하기로 설정된 태스크를 성공적으로 수행 한 것입니다. 메소드 firstLessThanSecond(int l, int r)가 있고 trueif l > r또는 falseif를 반환 하면 정상적으로 반환되지만 l <= r해당 메소드는 성공 하지 못합니다 .
저스틴 타임-복원 모니카

1
@JustinTime add은 계약의 약자입니다. 문서는 "지정된 요소가없는 경우이 세트에 지정된 요소를 추가합니다"로 시작하며 항목이 이미 세트에 있는지 여부에 만족합니다. 원하는대로 리턴 값을 해석 할 수는 있지만 궁극적으로 해석 값일뿐입니다. 그리고 두 번째 예제에서이 방법은 조건이 참인지 평가합니다. 조건이 거짓이면 조건을 성공적으로 평가 했으므로 메소드가 실패하지 않은 것입니다.
Reinstate Monica

2

나는 그것이 C와 같다고 말하고 싶다. 대부분의 경우 돌연변이 결과에 대해 설명 적으로 명명 된 변수를 사용하고 if조건 에서 돌연변이가 발생하지 않는 것을 선호합니다 .

컴파일러는이 변수가 즉시 재사용되면이 변수를 제거합니다. 인간은 더 쉽게 시간을 읽을 수있을 것입니다. 나에게 그것은 더 중요하다.

누군가가 if 조건에 and/ or절을 추가하여 조건을 확장 해야하는 .add()경우 단락 평가로 인해 특정 경우 호출하지 않을 수 있습니다 . 단락이 구체적으로 예상되지 않는 한 이것은 버그로 끝날 수 있습니다.


내가 쓴다면 if (set.contains(entry)){set.add(entry); //do more stuff}컴파일러에서도 제거됩니까?
Andreas Braun

1
@AndreasBraun : 나는 그렇게 생각하지 않습니다; 컴파일러 사이의 의미 적 연결에 대해 아무 생각이 없습니다 containsadd. 또한 entry세트에서 검색하는 이중 작업을 수행 합니다. 이것은 매우 큰 세트와 매우 가벼운 루프에 영향을 줄 수 있습니다.
9000

1
그래서 나는 당신이 오히려 글을 쓰지 if (set.contains(entry)){set.add(entry); //do more stuff}않고 대신 Karl Bielefeldt의 대답으로 가겠다 고 생각합니까?
Andreas Braun

@AndreasBraun : 정확히 (해답을 찬성했습니다).
9000

1
좋은 지적입니다. 미래 개발자가 단락이있는 다른 조건을 가질 수 있기 때문에 if의 돌연변이는 까다 롭습니다.
njzk2

0

코드가 Command Query Separation 을 위반하는 것 같습니다 . 이것은 Clean Code bookFunction Structure 비디오 에서 논의됩니다 . 그래서 Clean Code 관점에서 나는 그것이 좋은 스타일로 간주되지 않는다고 생각합니다.

“클린 코드는 간단하고 직접적입니다. 깨끗한 코드는 잘 작성된 산문처럼 읽습니다. 깔끔한 코드는 디자이너의 의도를 모호하게하지 않으며, 선명한 추상화와 간단한 제어 라인으로 가득합니다.

-응용 프로그램을 사용한 객체 지향 분석 및 디자인의 Grady Booch 저자”

나에게 당신의 코드의 의도는 분명하지 않습니다. 항목이 성공적으로 추가되거나 이미 존재하는 경우 if가 모두 실행됩니까? 무엇을 add()반환합니까? 물건? 오류 코드?


2
그래, 나도 그렇게 생각 했어. 그러나 @Kilian Foth도 지적하고 있습니다. 쿼리와 명령을 분리하려면 if (set.contains(entry)){set.add(entry); //do more stuff}어리석은 것 같아야합니다. 이것에 대해 무엇을 가져가십니까?
Andreas Braun

좋은 이름을 제안하기 위해이 코드의 도메인과 컨텍스트를 모르지만 명확한 의도로 함수로 래핑합니다. 예 : doesEntryExistOrCreateEntry (entry), contains () + add () 논리를 포함하고 부울을 리턴 할 수 있습니다. 비슷한 질문이 있습니다 : softwareengineering.stackexchange.com/questions/149708/… 이것은 깨끗한 코드 외부 에서이 관행을 설명합니다.
Niels van Reijmersdal

6
나는 명령 쿼리 분리 규칙이 특히 바보 같은 생각에 적용될 때 바보 같은 생각합니다. 여기서 메소드는 모두 작업을 수행하고 작업의 성공 상태를 반환합니다. 또한 규칙이 무엇인지 설명하거나 규칙의 정당화 방법을 많이 제공하지는 않습니다. 이러한 이유로 하향 투표되었습니다.

1
"add ()는 무엇을 반환합니까?" 코드 검토를 수행하는 Java 개발자는 CollectionAPI 를 알고 있어야합니다 .
njzk2

3
@ dan1111과 동의합니다. 그것은이다 특히 이 경쟁 조건에 대한 비옥 한 토양을 만드는 일의 종류이기 때문에 벙어리.
Paul Draper
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.