46. Exception classes should be immutable
Exception classes๋ ๋ถ๋ณํด์ผ ํฉ๋๋ค.
Exception์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ํ๋ฅผ ํํํ๋ ๊ฒ์ ์๋ฏธํ๋ค.
public class MyException extends Exception {
private int status; // Noncompliant
public MyException(String message) {
super(message);
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
public class MyException extends Exception {
private final int status; // Compliant
public MyException(String message, int status) {
super(message);
this.status = status;
}
public int getStatus() {
return status;
}
}
47. Exception handlers should preserve the original exception
Exception handlers ๋ ์๋ Excepion์ ๋ณด์กดํ๋ค.
๋ฐ์๋ ์๋ฌ๋ฅผ ์ฒ๋ฆฌํ ๋, ๋ฐ์ํ ์์ธ๋ฅผ ๊ทธ๋๋ก ํธ์ถํ ์ชฝ์ผ๋ก ์ ๋ฌ๋์ด์ผ ํฉ๋๋ค.
// Noncompliant - exception is lost
try { /* ... */ }catch (Exception e)
{ LOGGER.info("context"); }
// Noncompliant - exception is lost (only message
is preserved)
try { /* ... */ } catch (Exception e)
{ LOGGER.info(e.getMessage()); }
// Noncompliant - exception is lost
try { /* ... */ } catch (Exception e) { throw new
RuntimeException("context"); }
try { /* ... */ } catch (Exception e) { LOGGER.info(e); }
try { /* ... */ } catch (Exception e) { throw new
RuntimeException(e); }
try {
/* ... */
} catch (RuntimeException e) {
doSomething();
throw e;
} catch (Exception e) {
// Conversion into unchecked exception is also
allowed
throw new RuntimeException(e);
}
49. Exceptions should not be thrown from servlet methods
์์ธ๋ servlet methods์ ๋ฐ์๋์ด์๋ ์๋๋ค.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String ip = request.getRemoteAddr();
InetAddress addr = InetAddress.getByName(ip); // Noncompliant; getByName(String) throws
UnknownHostException
//...
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
try {
String ip = request.getRemoteAddr();
InetAddress addr = InetAddress.getByName(ip);
//...
}
catch (UnknownHostException uhex) {
//...
}
}
50. Exceptions should not be thrown in finally blocks
์์ธ ์์ finally ๋ธ๋ก์์ thrown ์ ํ๋ฉด ์๋๋ค
Flnally block์ ํ๋ก๊ทธ๋จ์ ์ํ ์ค ๋ฐ์ํ ์ ์๋ ์ด๋ ๋ฌธ์ ์ ๋ํด์๋ ์์์ ์์
์ ๋ง๊ณ ์์๋ณต๊ตฌ๋ฅผ ํ์คํํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค.
์ฆ, try-catch ๊ตฌ๋ฌธ์์ ์์ธ์ ๋ฐ์ ์ฌ๋ถ์ ์๊ด์์ด ์คํ๋์ด์ผ ํ ์ฝ๋๋ฅผ ๋ฃ๋ ๊ณณ์ด
finlly ๊ตฌ๋ฌธ์ด๋ค.
try {
/* some work which end up throwing an exception */
throw new IllegalArgumentException();
} finally {
/* clean up */
throw new RuntimeException(); // Noncompliant - will mask the IllegalArgumentException
}
try {
/* some work which end up throwing an exception */
throw new IllegalArgumentException();
} finally {
/* clean up */ // Compliant
}
51. Generic exceptions should never be thrown
์ผ๋ฐ์ ์ธ ์์ธ๋ ๊ฒฐ์ฝ thrown ํ๋ฉด ์๋๋ค.
public void foo(String bar) throws Throwable { // Noncompliant
throw new RuntimeException("My Message"); // Noncompliant
}
public void foo(String bar) {
throw new MyOwnRuntimeException("My Message");
}
52. HTTP referers should not be relied on
http referers์ ์์กดํด์๋ ์๋๋ค.
Referers๋ ๊ณต๊ฒฉ์์ ์ํด ์์ ์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ referers ๊ฐ์ ๋ํด์ ์ ๋ขฐํ์ง ๋ง
์๋ผ.
public class MyServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String referer = request.getHeader("referer"); // Noncompliant
if(isTrustedReferer(referer)){
//..
}
//...
}
}
53. IP addresses should not be hardcoded
IP์ฃผ์๋ฅผ ํ๋์ฝ๋ฉ ํ์ง ๋ง์๋ผ
์์ค์ฝ๋์ IP์ฃผ์๋ฅผ ํ๋ ์ฝ๋ฉํ๋ ๊ฒ์ ๋ํ ๋์ ์
โข ์ฃผ์๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ ์ฌ์ปดํ์ผ ํด์ผ ํจ
โข ๋ชจ๋ ํ๊ฒฝ์์ ๊ฐ์ ์ฃผ์๊ฐ ์ฌ์ฉ๋์ง ์๋๋ค.(๊ฐ๋ฐ, ๊ฒ์ฆ, ์ด์)
โข ๊ณต๊ฒฉ์๊ฐ ์ฝ๋๋ฅผ ๋์ปดํ์ผํ์ฌ ์ฃผ์๋ฅผ ์์๋ผ ์ ์๋ค.
String ip = "127.0.0.1";
Socket socket = new Socket(ip, 6667);
String ip = System.getProperty("myapplication.ip");
Socket socket = new Socket(ip, 6667);
54. Math operands should be cast before assignment
์ํ ์ฐ์ฐ์๋ ์ฌ์ฉํ๊ธฐ ์ ์ ์บ์คํ ํด์ผ ํ๋ค.
์ฐ์ฐ์ ๊ฒฝ์ฐ ๊ฒฐ๊ณผ๋ ํญ์ int์ผ ๊ฒ์ด๋ค.
float twoThirds = 2/3; // Noncompliant; int division. Yields 0.0
long millisInYear = 1_000*3_600*24*365; // Noncompliant; int multiplication. Yields 1471228928
long bigNum = Integer.MAX_VALUE + 2; // Noncompliant. Yields -2147483647
long bigNegNum = Integer.MIN_VALUE-1; //Noncompliant, gives a positive result instead of a negative
one.
Date myDate = new Date(seconds * 1_000); //Noncompliant, won't produce the expected result if
seconds > 2_147_483
...
public long compute(int factor){
return factor * 10_000; //Noncompliant, won't produce the expected result if factor > 214_748
}
float twoThirds = 2f/3; // 2 promoted to float. Yields 0.6666667
long millisInYear = 1_000L*3_600*24*365; // 1000 promoted to long. Yields 31_536_000_000
long bigNum = Integer.MAX_VALUE + 2L; // 2 promoted to long. Yields 2_147_483_649
long bigNegNum = Integer.MIN_VALUE-1L; // Yields -2_147_483_649
Date myDate = new Date(seconds * 1_000L);
...
public long compute(int factor){
return factor * 10_000L;
}
55. Member variable visibility should be specified
๋ฉค๋ฒ๋ณ์์ ๊ฐ์์ฑ์ ์ง์ ํด์ผ ํ๋ค.
class Ball {
String color="red"; // Noncompliant
}
enum A {
B;
int a;
}
class Ball {
private String color="red"; // Compliant
}
enum A {
B;
private int a;
}
56. Neither DES (Data Encryption Standard) nor DESede (3DES) should be
used
DES(๋ฐ์ดํฐ ์ํธํ ํ์ค) ๋ DESede(3DES) ๋ ์ฌ์ฉํ์ง ์๋๋ค.
ํ์ค ๋ฐ ๋ฏธ๊ตญ ๊ตญ๋ฆฝ ๊ธฐ์ ์ฐ๊ตฌ์ (NIST)์ ๋ฐ๋ฅด๋ฉด, ๋ฐ์ดํฐ ์ํธํ ํ์ค (DES)๋ ๋ ์ด์
์์ ํ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋์ง ์์ต๋๋ค
Cipher c = Cipher.getInstance("DESede/ECB/PKCS5Padding");
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
57. Null pointers should not be dereferenced
๋ํฌ์ธํฐ๋ ์ญ์ฐธ์กฐํด์๋ ์๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ๊ทธ ๊ฐ์ฒด๊ฐ NULL์ด ๋ ์ ์๋คโ๋ผ๊ณ ํ๋ ๊ฐ์ ์ ์๋ฐํ์ ๋ ๋ฐ์ํ๋ค.
@CheckForNull
String getName() {...}
public boolean isNameEmpty() {
return getName().length() == 0; // Noncompliant; the result of getName() could be null, but isn't null-
checked
}
Connection conn = null;
Statement stmt = null;
try {
conn = DriverManager.getConnection(DB_URL,USER,PASS);
stmt = conn.createStatement();
// ...
} catch(Exception e) {
e.printStackTrace();
} finally {
stmt.close(); // Noncompliant; stmt could be null if an exception was thrown in the try{} block
conn.close(); // Noncompliant; conn could be null if an exception was thrown
}
58. Only standard cryptographic algorithms should be used
๋จ์ง ํ์ค ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํด์ผ ํ๋ค.
์ค์ํ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ๋ฅผ ๋์คํฌ์ ์ ์ฅํ๊ฑฐ๋ ์ธ๋ถ ์ ์ก ์, SW๊ฐ ํด๋น ๋ฐ์ดํฐ๋ฅผ ์ํธ
ํํ์ง ์์ ๊ฒฝ์ฐ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ๊ฐ ๋ ธ์ถ๋ ์ ์๋ค.
ํ์ค์๊ณ ๋ฆฌ์ฆ : SHA-256, SHA-384, SHA-512
MyCryptographicAlgorithm extends MessageDigest {
...
}
59. Public methods should throw at most one checked exception
Public method ์์๋ ๋๋ถ๋ถ ํ๋์ exception์ ์ฒดํฌํ์ฌ throw ํ๋ค.
public void delete() throws IOException, SQLException { // Noncompliant
/* ... */
}
public void delete() throws SomeApplicationLevelException {
/* ... */
}
60. Resources should be closed
์์์ ๋ซ์์ผ ํ๋ค.
OutputStream stream = null;
try{
for (String property : propertyList) {
stream = new FileOutputStream("myfile.txt"); // Noncompliant
// ...
}
}catch(Exception e){
// ...
}finally{
stream.close(); // Multiple streams were opened. Only the last is closed.
}
OutputStream stream = null;
try{
stream = new FileOutputStream("myfile.txt");
for (String property : propertyList) {
// ...
}
}catch(Exception e){
// ...
}finally{
stream.close();
}
64. Useless "if(true) {...}" and "if(false){...}" blocks should be removed
์ธ๋ชจ์๋ If(true)์ if(false)๋ ์ ๊ฑฐ ๋์ผ ํฉ๋๋ค.
if (true) {
doSomething();
}
...
if (false) {
doSomethingElse();
}
if (2 < 3 ) { ... } // Noncompliant; always false
int i = 0;
int j = 0;
// ...
j = foo();
if (j > 0 && i > 0) { ... } // Noncompliant; always false - i never set after initialization
boolean b = true;
//...
if (b || !b) { ... } // Noncompliant
doSomething();
...
65. Values passed to OS commands should be sanitized
OS ๋ช ๋ น์ด๋ก ์ ๋ฌ๋ ๊ฐ์ ์ ๊ฑฐ ๋์ด์ผ ํ๋ค.
public void listContent(String input) {
Runtime rt = Runtime.getRuntime();
rt.exec("ls " + input); // Noncompliant; input could easily contain extra commands
...
}
public void execute(String command, String argument) {
ProcessBuilder pb = new ProcessBuilder(command, argument); // Noncompliant
...
}
66. Web applications should not have a "main" method
์น ์์ฉํ๋ก๊ทธ๋จ์ โmainโ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ง ๋ง์์ผ ํ๋ค.
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
if (userIsAuthorized(req)) {
updatePrices(req);
}
}
public static void main(String[] args) { // Noncompliant
updatePrices(req);
}
}
67. Web applications should use validation filters
์น ์์ฉํ๋ก๊ทธ๋จ์์ ๊ฒ์ฆ ํํฐ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
public class ValidatingHttpRequest extends HttpServletRequestWrapper {
// ...
}
public class ValidationFilter implements javax.servlet.Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
chain.doFilter(new ValidatingHttpRequest( (HttpServletRequest)request ), response);
}
}
<filter>
<filter-name>ValidationFilter</filter-name>
<filter-class>com.myco.servlet.ValidationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ValidationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
71. "entrySet()" should be iterated when both the key and value are
needed
key์ value๊ฐ ๋ชจ๋ ํ์ํ ๋ entrySet() ์ ๋ฐ๋ณตํด์ ์ฌ์ฉํด์ผ ํ๋ค.
HashMap์ entrySet ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ํค๊ฐ ๋ค์ด์๋ Set์ด ๋์ด ์ต๋๋ค.
Set์์ iterator๋ฅผ ๋ฝ์๋ด๋ฉด while ๋ฌธ์ผ๋ก ๋ฃจํ๋ฅผ ๋๋ ค์ ํค๋ฅผ ํ๋์ฉ ๊ฐ์ ธ์ฌ ์ ์์ต
๋๋ค.
public void doSomethingWithMap(Map<String,Object> map) {
for (String key : map.keySet()) { // Noncompliant; for each key the value is retrieved
Object value = map.get(key);
// ...
}
}
public void doSomethingWithMap(Map<String,Object> map) {
for (Map.Entry<String,Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// ...
}
}
72. "ResultSet.isLast()" should not be used
ResultSet.isLast()๋ฅผ ์ฌ์ฉํ์ง ๋ง์๋ผ.
stmt.executeQuery("SELECT name, address FROM PERSON");
ResultSet rs = stmt.getResultSet();
while (! rs.isLast()) { // Noncompliant
// process row
}
ResultSet rs = stmt.executeQuery("SELECT name, address FROM PERSON");
while (! rs.next()) {
// process row
}
73. "URL.hashCode" and "URL.equals" should be avoided
โURL.hashCodeโ ์ โURL.equalsโ๋ ํผํด์ผ ํ๋ค.
Equals์ hashCode ๋ฉ์๋๋ java.net.URL
public void checkUrl(URL url) {
Set<URL> sites = new HashSet<URL>(); // Noncompliant
URL homepage = new URL("http://sonarsource.com"); // Compliant
if (homepage.equals(url)) { // Noncompliant
// ...
}
}
public void checkUrl(URL url) {
Set<URI> sites = new HashSet<URI>(); // Compliant
URI homepage = new URI("http://sonarsource.com"); // Compliant
URI uri = url.toURI();
if (homepage.equals(uri)) { // Compliant
// ...
}
}
74. "wait(...)" should be used instead of "Thread.sleep(...)" when a lock is
held
โThread.sleep(โฆ)โ ๋์ ์ โwait(โฆ)โ์ ์ฌ์ฉ์ ์ ๊ธ์ด ์ ์ง ๋๋ค.
Wait() : ๋๊ธฐํ๋ ๋ค์ค์ค๋ ๋๊ฐ ๊ฐ์ ์ค๋ธ์ ํธ์ ์ ๊ทผํ๊ณ ์ ํ ๋ ์ค์ง์ํจ๋ค.
Sleep() : ๋๊ธฐํ๋ ๋ค์ค์ค๋ ๋๋ฅผ ์๊ฐ์ผ๋ก ์ค์ง์ํจ๋ค.
public void doSomething(){
synchronized(monitor) {
while(notReady()){
Thread.sleep(200);
}
process();
}
...
}
public void doSomething(){
synchronized(monitor) {
while(notReady()){
monitor.wait(200);
}
process();
}
...
}
75. Multiple loops over the same set should be combined
๊ฐ์ ์ค์ ์ ์ฌ๋ฌ ๋ฃจํ๋ ๊ฒฐํฉํด์ ์ฌ์ฉํ๋ค.
public void doSomethingToAList(List<String>
strings) {
for (String str : strings) {
doStep1(str);
}
for (String str : strings) { // Noncompliant
doStep2(str);
}
}
public void doSomethingToAList(List<String>
strings) {
for (String str : strings) {
doStep1(str);
doStep2(str);
}
}
76. Objects should not be created only to "getClass"
Object๋ฅผ ๋จ์ง getClass๋ก ์์ฑํ์ง ๋ง์๋ผ
getClass์ ํธ์ถ์ ๋ชฉ์ ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์ธ๋ฐ, ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ฒ ๋๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น
๊ฐ ๋ฐ์ํ๋ฏ๋ก ๋จ์ํ class๋ฅผ ์ฌ์ฉํฉ๋๋ค.
MyObject myOb = new MyObject(); // Noncompliant
Class c = myOb.getClass();
Class c = MyObject.class;
77. Sets with elements that are enum values should be replaced with
EnumSet
์ด๊ฑฐ ๊ฐ์ด ์๋ elements set๋ EnumSet ์ผ๋ก ๋์ฒดํด์ผ ํฉ๋๋ค.
public class MyClass {
public enum COLOR {
RED, GREEN, BLUE, ORANGE;
}
public void doSomething() {
Set<COLOR> warm = new HashSet<COLOR>();
warm.add(COLORS.RED);
warm.add(COLORS.ORANGE);
}
}
public class MyClass {
public enum COLOR {
RED, GREEN, BLUE, ORANGE;
}
public void doSomething() {
EnumSet<COLOR> warm =
EnumSet.of(COLOR.RED, COLOR.ORANGE);
}
}
78. String function use should be optimized for single characters
String function์ ํ๋์ ๊ธฐํธ์ ์ ํฉํ๋ค.
String myStr = "Hello World";
// ...
int pos = myStr.indexOf("W"); // Noncompliant
// ...
int otherPos = myStr.lastIndexOf("r"); // Noncompliant
// ...
String myStr = "Hello World";
// ...
int pos = myStr.indexOf('W');
// ...
int otherPos = myStr.lastIndexOf('r');
// ...
79. Strings should not be concatenated using '+' in a loop
๋ฌธ์์ด์ ๋ฃจํ์์ โ+โ์ ์ฌ์ฉํ์ฌ ์ฐ๊ฒฐ๋์ด์๋ ์๋๋ค.
๋ฌธ์์ด์ ๋ถ๋ณ๊ฐ์ฒด ์ ๋๋ค. ๊ทธ๋์ ์ฐ๊ฒฐ์ ๋จ์ํ ๊ธฐ์กด์ ๋ฌธ์์ด ๋์ ์๋ก์ด ๋ฌธ์์ด์
์ถ๊ฐ ํ์ง ์์ต๋๋ค. ๋์ ๊ฐ ๋ฃจํ๊ฐ ๋ฐ๋ณต๋๋ฉด์ ์ฒซ๋ฒ์งธ ๋ฌธ์์ด์ด ์ฐ๊ฒฐ๋๋ ๋ฌธ์์ด ํ
์์ผ๋ก ๋ณํ๋ฉ๋๋ค. ์ด๋ฐ์์ผ๋ก ๋ฌธ์์ด์ด ๊ธธ์ด์ง๋ฉด ์์ ์ ์ฑ๋ฅ์ ์ ํ๊ฐ ๋ฐ์ํ๊ฒ ๋ฉ
๋๋ค. ๋ฐ๋ผ์ StringBuilder์ ์ฌ์ฉ์ด ๋ฐ๋์งํฉ๋๋ค.
String str = "";
for (int i = 0; i < arrayOfStrings.length ; ++i) {
str = str + arrayOfStrings[i];
}
StringBuilder bld = new StringBuilder();
for (int i = 0; i < arrayOfStrings.length; ++i) {
bld.append(arrayOfStrings[i]);
}
String str = bld.toString();
80. Synchronized classes Vector, Hashtable, Stack and StringBuffer should
not be used
๋๊ธฐํ(Synchronized) classes๋ Vector, Hashtable, Stack and StringBuffer๋ฅผ ์ฌ์ฉ
ํ๋ฉด ์๋๋ค.
Vertor์ ๊ฒฝ์ฐ ๋ฌด์กฐ๊ฑด ๋๊ธฐํ์ด๊ธฐ ๋๋ฌธ์ ๋จ์ผ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ์๋ ์ฑ๋ฅ์ ํ๋ฅผ
๊ฐ์ ธ์ค๊ฒ๋ฉ๋๋ค.
- Vector ๋์ ์ ArrayList ๋๋ LinkedList๋ฅผ ์ฌ์ฉ
- Stack ๋์ ์ Deque๋ฅผ ์ฌ์ฉ
- Hashtable ๋์ ์ HashMap ์ฌ์ฉ
- StringBuffer ๋์ ์ StringBuilder ์ฌ์ฉ
Vector cats = new Vector();
ArrayList cats = new ArrayList();