API는 호출자와 피호출자 간의 계약입니다. 가장 흔한 형태의 API 오용은 호출자가 이 계약에서 자신의 몫을 이행하지 못하기 때문에 발생합니다. 예를 들어, 프로그램이 chroot()를 호출한 후 chdir()을 호출하지 못하면 활성 루트 디렉터리를 안전하게 변경하는 방법을 지정하는 계약을 위반하는 것입니다. 라이브러리 오용의 또 다른 좋은 예는 피호출자가 호출자에게 신뢰할 만한 DNS 정보를 반환할 것으로 예상하는 것입니다. 이 경우, 호출자는 자신의 행동에 대해 특정한 가정을 함으로써(반환 값이 인증 목적으로 사용될 것으로 예상) 피호출자 API를 오용합니다. 다른 쪽에서 호출자-피호출자 계약을 위반할 수도 있습니다. 예를 들어, 코더가 하위 클래스 SecureRandom을 지정하고 임의 값이 아닌 값을 반환하는 경우 계약을 위반하는 것입니다.
Equals()
는 Equals()
를 구현하지 않는 개체에서 호출됩니다.Equals()
를 명시적으로 구현하지 않는 클래스(또는 임의의 수퍼 클래스/인터페이스)에서 Equals()
를 호출하면 System.Object
에서 상속된 Equals()
메서드를 호출하게 됩니다. 개체 멤버 필드 또는 기타 속성을 비교하는 대신, Object.Equals()
는 동일한지 알아보기 위해 두 개의 개체 인스턴스를 비교합니다. Object.Equals()
를 올바르게 사용하더라도 때때로 버그가 있는 코드가 있음을 나타낼 수 있습니다.
public class AccountGroup
{
private int gid;
public int Gid
{
get { return gid; }
set { gid = value; }
}
}
...
public class CompareGroup
{
public bool compareGroups(AccountGroup group1, AccountGroup group2)
{
return group1.Equals(group2); //Equals() is not implemented in AccountGroup
}
}
equals()
메서드는 equals()
를 구현하지 않는 개체에서 호출됩니다.equals()
를 명시적으로 구현하지 않는 클래스(또는 임의의 수퍼 클래스/인터페이스)에서 equals()
를 호출하면 java.lang.Object
에서 상속된 equals()
메서드를 호출하게 됩니다. 개체 멤버 필드 또는 기타 속성을 비교하는 대신, Object.equals()
는 동일한지 알아보기 위해 두 개의 개체 인스턴스를 비교합니다. Object.equals()
를 올바르게 사용하더라도 때때로 버그가 있는 코드가 있음을 나타낼 수 있습니다.
public class AccountGroup
{
private int gid;
public int getGid()
{
return gid;
}
public void setGid(int newGid)
{
gid = newGid;
}
}
...
public class CompareGroup
{
public boolean compareGroups(AccountGroup group1, AccountGroup group2)
{
return group1.equals(group2); //equals() is not implemented in AccountGroup
}
}
finalize()
메서드는 super.finalize()
를 호출해야 합니다.finalize()
메서드로 super.finalize()
를 호출하는 것이 좋은 방법이라고 설명합니다[1].super.finalize()
호출이 생략된 것입니다.
protected void finalize() {
discardNative();
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException;
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
private void readObjectNoData() throws ObjectStreamException;
getOutputStream
호출 후 getWriter()
를 호출하거나 그 반대로 수행하는 경우도 잘못입니다.HttpServletRequest
을 전달하거나, HttpServletResponse
를 리디렉션하거나 서블릿의 출력 스트림 버퍼를 플러시하면 연결된 스트림이 커밋됩니다. 추가 플러시 또는 리디렉션 등, 이어지는 버퍼 재설정 또는 스트림 커밋은 IllegalStateException
으로 이어질 수 있습니다.ServletOutputStream
또는 PrintWriter
중 하나를 사용하여(두 가지 모두는 안 됨) 응답 스트림에 데이터를 쓸 수 있습니다. getOutputStream()
을 호출한 후 getWriter()
를 호출하거나 또는 그 반대의 경우에도 IllegalStateException
이 발생합니다.IllegalStateException
은 응답 핸들러가 실행 완료되는 것을 막아 응답을 취소합니다. 이로 인해 서버 불안정이 발생할 수 있는데, 이는 서블릿이 잘못 구현되었다는 의미입니다.예제 2: 반대로 다음 코드는 요청이 전달되고 나면
public class RedirectServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
...
OutputStream out = res.getOutputStream();
...
// flushes, and thereby commits, the output stream
out.flush();
out.close(); // redirecting the response causes an IllegalStateException
res.sendRedirect("http://www.acme.com");
}
}
PrintWriter
의 버퍼에 쓰거나 플러시를 시도합니다.
public class FlushServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
...
// forwards the request, implicitly committing the stream
getServletConfig().getServletContext().getRequestDispatcher("/jsp/boom.jsp").forward(req, res);
...
// IllegalStateException; cannot redirect after forwarding
res.sendRedirect("http://www.acme.com/jsp/boomboom.jsp");
PrintWriter out = res.getWriter();
// writing to an already-committed stream will not cause an exception,
// but will not apply these changes to the final output, either
out.print("Writing here does nothing");
// IllegalStateException; cannot flush a response's buffer after forwarding the request
out.flush();
out.close();
}
}
Content-Length
헤더가 음수로 설정됩니다.Content-Length
헤더를 설정한다는 것은 개발자가0
또는Content-Length
를 설정합니다.
URL url = new URL("http://www.example.com");
HttpURLConnection huc = (HttpURLConnection)url.openConnection();
huc.setRequestProperty("Content-Length", "-1000");
Content-Length
헤더가 음수로 설정됩니다.Content-Length
헤더를 설정한다는 것은 개발자가0
또는Content-Length
헤더를 음수로 잘못 설정합니다.
xhr.setRequestHeader("Content-Length", "-1000");
ToString()
이 배열에서 호출됩니다.ToString()
의 호출은 개발자가 배열의 내용을 문자열로 반환하는 데 관심이 있다는 의미입니다. 그러나 배열에서 ToString()
을 직접 호출하면 배열의 형식을 포함하는 문자열 값이 반환됩니다.System.String[]
을 출력합니다.
String[] stringArray = { "element 1", "element 2", "element 3", "element 4" };
System.Diagnostics.Debug.WriteLine(stringArray.ToString());
toString()
이 배열에서 호출됩니다.toString()
의 호출은 개발자가 배열의 내용을 문자열로 반환하는 데 관심이 있다는 의미입니다. 그러나 배열에서 toString()
을 직접 호출하면 배열의 형식 및 메모리의 해시코드를 포함하는 문자열 값이 반환됩니다.[Ljava.lang.String;@1232121
을 출력합니다.
String[] strList = new String[5];
...
System.out.println(strList);