소스코드

package superCode;

public class Sjh_test {

	public static void main(String[] args) {
//		[문제] 
//			7의 배수 중 작은수부터 3개만 출력하시오.
//		[정답]
//			7, 14, 21
		
		1번째 방법
//		int i = 1;
//		int count = 0;
//		
//		while(i <= 25) {
//			
//			if(i % 7 == 0) {
//				System.out.print(i + " ");
//				count = count + 1;
//			}
//			i += 1;
//		}
//		System.out.println();
//		System.out.println("7의 배수 개수는 = " + count + "개");
		
		2번째 방법
		int i = 7;
		int count = 0;
		
		// 무한 반복
		boolean run = true;
		
		while(run) {
			// i가 7의 배수가 될 때마다 count + 1씩 증가
			if(i % 7 == 0) {
				System.out.println(i); // i 7의 배수가 될 때마다 i가 출력
				count = count + 1;
			}
			// count가 3이 될 때 반복 중단 
			if(count == 3) {
				run = false;
			}
			i += 1;
		}
	}

}

 

결과

소스코드

package superCode;

public class Sjh_test {

	public static void main(String[] args) {
//		[문제] 
//			1 ~ 10 까지 반복문을 실행하고
//			3의 배수의 개수를 출력하시오.
//		[정답]
//			3
		
		int i = 1;
		int count = 0;
		
		while(i <= 10) {
			
			if(i % 3 == 0) {
				System.out.println(i + " ");
				count = count + 1;
				
			}
			i++;
		}
		System.out.println("3의 배수의 개수는 = " + count);
		
	}

}

 

결과

package superCode;

public class Sjh_test {

	public static void main(String[] args) {
//		[문제] 
//			1 ~ 5 까지의 합을 출력하시오.
//			1 + 2 + 3 + 4 + 5
//		[정답]
//			15
		
		int i = 1;
		int sum = 0;
		
		while(i <= 5) {
			
			sum += i;
			
			i++;
			
		}System.out.println(sum);
		
		
	}

}

소스 코드

 

package superCode;

public class Sjh_test {

	public static void main(String[] args) {
//		[문제] 아래 조건을 충족하는 식을 작성하시오.
//			조건1) 10 ~ 1 까지 거꾸로 반복문을 실행한다.
//			조건2) 3 ~ 6 사이는 "안녕"을 출력한다.
//			조건3) 3 ~ 6 사이가 아닐때는 숫자를 출력한다.
		
		int i = 10;
//			조건1) 10 ~ 1 까지 거꾸로 반복문을 실행한다.
		while(i >= 1) {

			
//			조건2) 3 ~ 6 사이는 "안녕"을 출력한다.
			if(3 <= i && i <= 6) {
				System.out.println("안녕");
//			조건3) 3 ~ 6 사이가 아닐때는 숫자를 출력한다.	
			}else {
				System.out.println(i);
			}
			
			i -= 1;
		}
		
		
	}

}

 

결과

필드

필드 사용

클래스 내부의 생성자나 메소드에서 사용할 경우 단순히 필드 이름으로 읽고 변경이 가능

클래스 외부에서 사용할 경우 운선적으로 클래스로부터 객체를 생성한 뒤 필드 사용

 

Car 클래스 

public class Car {
	//필드
	int speed;
	
	//생성자
	Car(){
		speed = 0; // 필드 값 변경
	}
	
	//메소드
	void method() {
		speed = 10; // 필드 값 변경
	}
	
	
}
public class Person {
	// 외부 Person 클래스에서 Car클래스의 speed 필드 값 사용 가능
	
	void method() {
	
	// Car 객체 생성
	Car myCar = new Car();

	// 필드 사용
	myCar.speed=60; // 값 변경
    
	}
    
    
    
    // 필드 사용 2
    Car myCar2 = new Car();
    
    System.out.println("제작회사:" + myCar2.company);
	System.out.println("모델명:" + myCar2.model);
	System.out.println("색깔:" + myCar2.color);
	System.out.println("최고속도:" + myCar2.maxSpeed);
	System.out.println("현재속도:" + myCar2.speed);
    
}

 

 

 

 

 

생성자

생성자는 new 연산자로 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당

객체 초기화란 필드를 초기화하거나 메소드를 호출해서 객체를 사용할 준비를 하는 것

 

 

 

기본 생성자

모든 클래스는 생성자가 반드시 존재하며, 생성자를 하나 이상 가질 수 있음

중괄호 {} 블록 내용이 비어 있는 기본생성자를 바이트 코드에 자동 추가 ( 생략 가능 )

클래스에 명시적으로 선언한 생서자가 1개라도 있으면 컴파일러는 기본 생성자를 추가하지 않음

명시적으로 생성자를 선언하는 이유는 객체를 다양한 값으로 초기화하기 위해서

 

 

생성자 선언

생성자는 메소드와 비슷한 모양을 가지고 있으나, 리턴 타입이 없고 클래스 이름과 동일

일반적으로 필드에 초기값을 저장하거나 메서드를 호출하여 객체 사용 전에 필요한 준비를 함

매개 변수는 new 연산자로 생성자를 호출할 때 외부의 값을 생성자 블록 내부로 전달하는 역할을 함

명시적 호출 예)

package choongang;

public class Car {
	// 명시적으로 생성자 선언
	Car(String color, int cc){
		
	}
	
	
}


package choongang;

public class CarEx {

	public static void main(String[] args) {
		
//		Car myCar = new Car(); 기본 생성자를 호출할 수 없음
		
	Car클래스에 명시적으로 선언이 되어있기 떄문에 해당 처럼만 호출 가능
		Car myCar = new Car("검정", 3000);

	}

}

 

 

필드 초기화

클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동 설정

다른 값으로 초기화 방법은 두가지가 있음

1. 필드를 선언할 때 초기값을 주는 방법

필드를 선언할 때 초기값을 주게 되면 동일한 클래스로부터 생성되는 객체들은 모두 같은 값을 갖게 됨

package choongang;

public class Car {
	// 필드
	String nation = "대한민국";
	String name;
	String ssn;
	
	
}


package choongang;

public class CarEx {

	public static void main(String[] args) {
		
		Car car1 = new Car();
		System.out.println(car1.nation);
		
		Car car2 = new Car();
		System.out.println(car2.nation);
		
	}

}

 car1, car2 객체를 생성하게 되면 둘 다 nation 필드에는 "대한민국"이 저장 되 있음

 

 

2. 생성자에서 초기값을 주는 방법

public class Car {
	// 필드
	String nation = "대한민국";
	String name;
	String ssn;
	
	// 생성자
	public Car(String n, String s) {
		name = n;
		ssn = n;
	}
	
}


package choongang;

public class CarEx {

	public static void main(String[] args) {
		
		Car car1 = new Car("이자바", "010-1234-4567");
		System.out.println("car1.name = " + car1.name);
		System.out.println("car1.ssn = " + car1.ssn);
		
		Car car2 = new Car("김자바", "010-7894-1478");
		System.out.println("car2.name = " + car2.name);
		System.out.println("car2.ssn = " + car2.ssn);
		
	}

}
결과
car1.name = 이자바
car1.ssn = 이자바
car2.name = 김자바
car2.ssn = 김자바

 

 

'this.'

코드의 가독성을 높일라면 초기화시킬 필드 이름과 비슷하거나 동일한 이름을 사용하는 것이 좋음

일반적으로 필드와 동일한 이름을 갖는 매개 변수를 사용

그러나 이 경우 필드와 매개 변수 이름이 동일하기 때문에 생성자 내부에서 해당 필드에 접근 불가

왜냐하면 동일한 이름의 매개 변수가 사용 우선순위가 높기 때문에

해결 방법은 필드 앞에 'this.'를 붙이면 됨, this는 객체 자신의 참조

'this.필드'는 this라는 참조 변수로 필드를 사용하는 것과 동일

 

 

생성자 오버로딩

외부에서 제공되는 다양한 데이터들을 이용해서 객체를 초기화하려면 생성자도 다양화될 필요가 있음

생성자 오버로딩이란 매개 변수를 달리하는 생성자를 여러 개 선언하는 것을 의미

매개 변수의 타입, 개수, 순서가 다르게 선언되어야 함

package choongang;

public class Car {
	// 필드
    String company = "현대자동차";
	String model;
	String color;
	int maxSpeed;
	
	Car(){ // 1.생성자
		
	};
	
	Car(String model){ // 2.생성자
		this.model = model;
	}
	
	Car(String model, String color){ // 3.생성자
		this.model = model;
		this.color = color;
	};
	
	Car(String modle, String color, int maxSpeed){ // 4.생성자
		this.model = modle;
		this.color = color;
		this.maxSpeed = maxSpeed;
	}
	
}

package choongang;

public class CarEx {

	public static void main(String[] args) {
		
		Car car1 = new Car();
		System.out.println("[1.생성자 선택] = " + car1.company);
		
		System.out.println();
		
		Car car2 = new Car("자가용");
		System.out.println("[2.생성자 선택] = " + car2.company);
		System.out.println("[2.생성자 선택] = " + car2.model);
		
		System.out.println();
		
		Car car3 = new Car("자가용", "레드");
		System.out.println("[3.생성자 선택] = " + car3.company);
		System.out.println("[3.생성자 선택] = " + car3.model);
		System.out.println("[3.생성자 선택] = " + car3.color);
		
		System.out.println();
		
		Car car4 = new Car("자가용", "레드", 250);
		System.out.println("[4.생성자 선택] = " + car4.company);
		System.out.println("[4.생성자 선택] = " + car4.model);
		System.out.println("[4.생성자 선택] = " + car4.color);
		System.out.println("[4.생성자 선택] = " + car4.maxSpeed);
	}

}

결과
[1.생성자 선택] = 현대자동차

[2.생성자 선택] = 현대자동차
[2.생성자 선택] = 자가용

[3.생성자 선택] = 현대자동차
[3.생성자 선택] = 자가용
[3.생성자 선택] = 레드

[4.생성자 선택] = 현대자동차
[4.생성자 선택] = 자가용
[4.생성자 선택] = 레드
[4.생성자 선택] = 250

 

 

 

다른 생성자 호출 : this()

 

생성자 오버로딩이 많아질 경우 생성자 간의 중복된 코드가 발생할 수있음

매개 변수의 수만 달리하고 필드 초기화 내용이 비슷한 생성자에서 이러한 현상을 보임

이 경우에는 필드 초기화 내용은 한 생성자에만 집중적으로 작성하고

나머지 생성자는 초기화 내용을 가지고 있는 생성자를 호출하는 방법으로 개선이 가능

생성자에서 다른 생성자를 호출할 때에는 다음과 같이 this() 코드를 사용

this()는 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫 줄에서만 허용 

this()의 매개값은 호출되는 생성자의 매개 변수에 맞게 제공해야 함

public class Car {
	// 필드
    String company = "현대자동차";
	String model;
	String color;
	int maxSpeed;
	
	Car(){ // 기본 생성자 생략 가능
		
	};
	
	Car(String model){ // 밑에 공통 실행 코드 호출
		this(model, "은색", 250);
	}
	
	Car(String model, String color){ // 밑에 공통 실행 코드 호출 
		this(model, color, 250);
		
	};
	
	// 공통 실행 코드 
	Car(String modle, String color, int maxSpeed){ 
		this.model = modle;
		this.color = color;
		this.maxSpeed = maxSpeed;
	}
	
}


public class CarEx {

	public static void main(String[] args) {
		
		Car car1 = new Car();
		System.out.println("[car1.company] = " + car1.company);
		
		System.out.println();
		
		Car car2 = new Car("자가용");
		System.out.println("[car2.company] = " + car2.company);
		System.out.println("[car2.model] = " + car2.model);
		
		System.out.println();
		
		Car car3 = new Car("자가용", "레드");
		System.out.println("[car3.company] = " + car3.company);
		System.out.println("[car3.model] = " + car3.model);
		System.out.println("[car3.color] = " + car3.color);
		
		System.out.println();
		
		Car car4 = new Car("택시", "검정", 300);
		System.out.println("[car4.company] = " + car4.company);
		System.out.println("[car4.model] = " + car4.model);
		System.out.println("[car4.color] = " + car4.color);
		System.out.println("[car4.maxSpeed] = " + car4.maxSpeed);
	}

}
결과
[car1.company] = 현대자동차

[car2.company] = 현대자동차
[car2.model] = 자가용

[car3.company] = 현대자동차
[car3.model] = 자가용
[car3.color] = 레드

[car4.company] = 현대자동차
[car4.model] = 택시
[car4.color] = 검정
[car4.maxSpeed] = 300

 

 

메소드

메소드는 객체의 동작에 해당하는 중괄호 { } 블록을 말합니다.

중괄호 블록 이름이 메소드 이름이며, 메소드를 호출하면 중괄호 블록에 있는 모든 코드들이

일괄적으로 실행됩니다.

 

메소드 선언

메소드 선언은 선언부( 리턴 타입, 메소드 이름, 매개 변수 선언 ) 와 실행 블록으로 구성

 

리턴 타입

리턴 타입은 리턴값의 타입을 말함, 리턴값이란 메소드를 실행한 후의 결과값을 말함

메소드는 리턴값이 있을 수도 있고 없을 수도 있으나

리턴값이 있을 경우 리턴 타입이 선언부에 명시되어야 함

메소드 선언
package choongang;

public class Car {
	
	void powerOn() {
		System.out.println("전원 ON");
	}
	
	int divide (int x, int y) {
		return x + y;
	}
	
}


메소드 호출 
package choongang;

public class CarEx {

	public static void main(String[] args) {
		
		Car car = new Car();
		
//		리턴값이 없는 메소드 호출 ( 매개변수 필요 X )
		car.powerOn();
		
//		리턴값이 있는 메소드 호출 ( 매개변수 필요 O )		
		double result1 = car.divide(10, 20);
		System.out.println("result1 = " + result1);
		
		// double 값을 저장할 수 없기 때문에 컴파일 에러 발생
//		int result2 = car.divide(10, 20);
		

	}

}
결과
전원 ON
result1 = 30.0

 

 

메소드 이름

1. 숫자로 시작하면 안 되고 $와 _ 를 제외한 특수 문자를 사용하지 말아야 함

2. 관례적으로 메소드 이름은 소문자로 작성

3. 서로 다른 단어가 혼합된 이름이라면 뒤이어 오는 단어의 첫 글자는 대문자로

잘 작성된 메소드 이름
void run(){...};
void startEngine(){...};
String getName(){...};
int[] getScores(){...};

 

 

매개 변수 선언

매개 변수는 메소드가 실행할 때 필요한 데이터를 외부로부터 받기 위해 사용

리턴값이 없는 경우 매개 변수 선언 필요 없음

리턴값이 있는 경우 매개 변수 개수에 따라 필요 함

 

선언
package choongang;

public class Car {
	
	
	double divide (int x, int y) {
		return x + y;
		
		
	}
	
}


호출
package choongang;

public class CarEx {

	public static void main(String[] args) {
		
		Car car = new Car();
		
//		리턴값이 있는 메소드 호출 ( 매개변수 2개 필요  )		
		double result1 = car.divide(10, 20);
		System.out.println("result1 = " + result1);
		
//		10.5와 20.0은 double 값이므로 int 타입으로 변환될 수 없기 때문에 컴파일 에러
//		double result2 = car.divide(10.5, 20.0);
		
//		byte는 int로 자동 타입 변환되기 떄문에 컴파일 에러가 안남
		byte b1 = 10;
		byte b2 = 20;
		double result3 = car.divide(b1, b2);
		System.out.println("result3 = " + result3);
		

	}

}

 

 

매개 변수의 개수를 모를 경우

메소드의 매개 변수는 개수가 이미 정해져 있는 것이 일반적이지만,

예를 들어 여러 개의 수를 모두 합산하는 메소드를 선언해야 한다면 몇 개의 매개 변수가

입력될지 알 수 없기 때문에 매개 변수의 개수를 결정 할 수 없을 것이다.

해결책은 매개 변수를 배열 타입으로 선언하는 것

선언
package choongang;

public class Car {
	
	
	int sum(int []values) {
		int sum = 0;
		for(int i=0; i<values.length; i++) {
			sum += values[i];
		}
		return sum;
	}
	
}


호출
package choongang;

public class CarEx {

	public static void main(String[] args) {
		
		Car car = new Car();
		
		// 1. 방법 
		int[] values = {1, 2, 3};
		int result1 = car.sum(values);
		System.out.println("result1 = " + result1);
		
		// 2. 방법
		int result2 = car.sum(new int[] {1, 2, 3, 4, 5});
		System.out.println("result2 = " + result2);

	}

}
결과
result1 = 6
result2 = 15

 

 

 

리턴(return)문

리턴값이 있는  메소드

메소드 선언에 리턴 타입이 있는 메소드는 반드시 리턴문을 사용해서 리턴값을 지정해야 함

return문이 없다면 컴파일 에러가 발생함

return문이 실행되면 메소드는 즉시 종료 / return문 이후의 실행문은 결코 실행되지 않음

int인 plus()메소드에서는 byte, short, int의 값이 리턴되어도 상관 없음 ( 자동 타입 변환 )

선언
package choongang;

public class Car {
	
	
	int plus( int x, int y ) {
		int result1 = x + y;
		System.out.println(result1);
	    return result1;
	}
	// 자동 타입 변환
	int plus2( int x, int y ) {
		byte result2 = (byte) (x + y);
		System.out.println(result2);
	    return result2;
	}
	
	// 컴파일 에러 
//	int plus3( int x, int y ) {
//		double result3 = (double) (x + y);
//		System.out.println(result3);
//	    return result3;
//	}
	
}


호출
package choongang;

public class CarEx {

	public static void main(String[] args) {
		
		Car car = new Car();
		
		car.plus(10, 20);
		
		car.plus2(10, 20);
		

	}

}
결과
30
30

 

 

리턴값이 없는 메소드 : void

리턴값이 없는 메소드는 리턴 타입으로 void를 사용

void로 선언된 메소드에서도 return문을 사용할 수 있음

이 경우 리턴값을 지정하는 것이 아니라 메소드 실행을 강제 종료

	void run() {
		while(true) {
			if(gas > 0) {
				System.out.println("달립니다.(gas잔량 : " + gas +")");
				gas -= 1;
			}else {
				System.out.println("멈춥니다.(gas잔량 : " + gas +")");
				return; // run() 메소드 실행 종료
			}
		} while문 뒤에 실행문이 추가적으로 더 있을 경우 break문을 반드시 사용
	}

 

 

 

메소드 호출

메소드는 클래스 내 . 외부의 호출에 의해 실행 된다.

클래스 내부의 다른 메소드에서 호출할 경우 단순한 메소드 이름으로 호출하면 되지만,

클래스 외부에서 호출할 경우 우선 클래스로부터 객체를 생성한 뒤 참조 변수를 이용해서 메소드 호출

객체가 존재해야 메소드도 존재하기 때문이다.

 

 

객체 내부에서 호출

메소드가 매개변수를 가지고 있을 때에는 매개변수의 타입과 수에 맞게 매개값을 제공

메소드(매개값, ...);

 

 

메소드가 리턴값이 없거나, 있어도 받고 싶지 않을 경우 아래와 같이 모두 호출이 가능

 

리턴값이 있는 메소드를 호출하고 리턴값을 받고 싶다면 밑에 처럼 변수를 선언하고 리턴값을 대입

이때 변수 타입은 메소드 리턴 타입과 동일하거나, 자동 타입 변환이 될 수 있어야 한다는 점에 주의

예를 들어 int는 double 타입으로 자동 변환되기 때문에 int 리턴값은 double 타입 변수에 대입할 수 있음

package choongang;

public class Car {
	
	int method1(int x, int y) {
		int result = x + y;
		return result;
	}
	
	void method2() {
		int result1 = method1(10, 20); // result1에는 30이 저장
		double result2 = method1(10, 20); // result2에는 30.0이 저장
	}
	
	
	}

선언 ( 호출순서 )
package sec031.exam03;

public class Calculator {
	
	//메서드 호출 순서
	//선언

	int plus(int x, int y) {
		
		int result = x + y;
		System.out.println("plus 실행 후 리턴값 : " + result);
		return result;
	}
	
	double avg(int x , int y) {
		
		double sum = plus(x, y);
		double result = sum /2;
		System.out.println("avg 실행 후 리턴값 : " + result);
		return result;
	}
	
	void execute() {
		System.out.println("execute");
		double result = avg(7, 10);
		println("실행결과: " + result);
	}
	
	void println(String messge) {
		System.out.println("println");
		System.out.println(messge);
	}
		

	

}


호출 ( 호출순서 )
package sec031.exam03;

public class CalculatorExample {

	public static void main(String[] args) {
		//메서드 호출 순서
		//호출
		
		Calculator mycalc = new Calculator();
		mycalc.execute();

	}

}

실행 순서 확인( 햇갈릴때는 print 해보면서 체크 )
execute
plus 실행 후 리턴값 : 17
avg 실행 후 리턴값 : 8.5
println
실행결과: 8.5

햇갈릴때는 print 해보면서 체크

 

 

 

객체 외부에서 호출

외부 클래스에서 메소드를 호출하려면 클래스로부터 객체를 생성해야 한다.

메소드는 객체에 소속된 멤버이므로 객체가 존재하지 않으면 메소드도 존재하지 않기 때문에

객체가 생성되었다면 참조 변수와 할께 도트(.) 연산자를 사용해서 메소드를 호출할 수 있음

 

-객체 생성-
클래스 참조변수 = new 클래스 ( 매개값, ... );
예) Car mycar = new Car();

-메소드 호출-
참조변수.메소드( 매개값, ... ); // 리턴값이 없거나, 있어도 리턴값을 받지 않을 경우
예) mycar.run();

타입 변수 = 참조변수.메소드( 매개값, ... ); // 리턴값이 있고, 리턴값을 받고 싶을 경우
예) int.speed = mycar.getSpeed();

 

 

메소드 오버로딩

클래스 내에 같은 이름의 메소드를 여러 개 선언하는 것을 메소드 오버로딩이라고 함

하나의 메소드 이름으로 여러 기능을 담는다라고 생각하면 됨

메소드 오버로딩 조건은 매개 변수의 타입, 개수, 순서 중 하나가 달라야 함 ( 매개순 )

메소드 오버로딩이 필요한 이유는 매개값을 다양하게 받아 처리할 수 있도록 하기 위해서

 

실습 예제 1

선언

package sec031.exam03;

public class Printer {
	// 메소드 오버로딩 문제 
	// 선언
	
	int x;
	
	void println() {
		
	}
	void println(int x) {
		System.out.println(x);
	}
	
	void println(boolean x) {
		System.out.println(x);
	}
	
	void println(double x) {
		System.out.println(x);
	}
	void println(String x) {
		System.out.println(x);
	}
}


호출

package sec031.exam03;

public class PrinterEx {
	// 메소드 오버로딩 문제 
	// 호출
	
	public static void main(String[] args) {
		Printer printer = new Printer();
		printer.println(10);
		printer.println(true);
		printer.println(5.7);
		printer.println("홍길동");
		
		

	}

}
결과
10
true
5.7
홍길동

실습 예제 2

선언

package sec031.exam03;

public class Calculator2 {
	// 메서드 오버로딩
	// 선언
	int divide(int x, int y) {
		System.out.println("int");
		return x / y;
	}
	double divide(double x, double y) {
		System.out.println("double");
		return x / y;
	}
}


호출

package sec031.exam03;

public class CalEx2 {
	
	// 메서드 오버로딩
		// 호출

	public static void main(String[] args) {
		Calculator2 cal = new Calculator2();
		System.out.println(cal.divide(10, 3));
		
		System.out.println(cal.divide(10, 3.0));
		// 자동 형변환 int => double

	}

}
결과
int
3
double
3.3333333333333335

실습 예제 3

선언

package sec03.exam03;

public class Square {
	// 메소드 오버로딩 ( 선언 ) 
	// 정사각형, 직사각형 넓이 
	
	// 정사각형의 넓이
	double square(double width) {
		return width * width;
	}
	
	// 직사각형의 넓이
	double rectangle(double width, double height) {
		return width * height;
	}
}


호출

package sec03.exam03;

public class SquareEx {
	// 메소드 오버로딩 ( 호출 )
	// 정사각형, 직사각형 넓이 
	
	public static void main(String[] args) {
		Square mySquare = new Square();
		
		// 정사각형의 넓이 구하기
		double result1 = mySquare.square(10);
		
		// 직사각형의 넓이 구하기
		double result2 = mySquare.rectangle(10, 20);
		
		// 결과 출력
		System.out.println("정사각형의 넓이 : " + result1);
		System.out.println("직사각형의 넓이 : " + result2);

	}

}
결과
정사각형의 넓이 : 100.0
직사각형의 넓이 : 200.0

+ Recent posts