class HashMapEx4 {
public static void main(String[] args) {
String[] data = { "A","K","A","K","D","K","A","K","K","K","Z","D" };
HashMap map = new HashMap();
}
}
실행결과
A : ### 3
D : ## 2
Z : # 1
K : ###### 6
package com.test.memo;
import java.util.HashMap;
public class Practice2 {
public static void main(String[] args) throws Exception {
String[] data = { "A", "K", "A", "K", "D", "K", "A", "K", "K", "K", "Z", "D" };
HashMap<String, Integer> map = new HashMap<>();
// 데이터 배열에서 각 문자의 출현 빈도를 카운트하여 map에 저장
for (String s : data) {
// map에 해당 문자가 이미 있는 경우 기존 값에서 1을 증가시키고,
// 없는 경우 1로 초기화하여 추가
map.put(s, map.getOrDefault(s, 0) + 1);
}
// map을 이용하여 출력 형식에 맞게 결과 출력
for (String key : map.keySet()) {
System.out.print(key + " : ");
for (int i = 0; i < map.get(key); i++) {
System.out.print("#");
}
System.out.println(" " + map.get(key));
}
}
}
map.put(s, map.getOrDefault(s, 0) +1
getOrDefault(s, 0)메서드는 s값이(key)에 이미 존재하는 경우 해당 value가 반환되고, 존재하지 않은경우 기본값으로 설정한 0이 반환된다. >> 뒤에 +1을 하는 이유는, 해당값이 존재하면 +1시켜야하고 존재하지 않아도 새로 +1해야하기때문에 따로 +1시켜주는 것이다. class TreeMapEx1 {
public static void main(String[] args) {
String[] data = { "A","K","A","K","D","K","A","K","K","K","Z","D" };
TreeMap map = new TreeMap();
}
}
실행결과
= 기본정렬 =
A : ### 3
D : ## 2
K : ###### 6
Z : # 1
= 값의 크기가 큰 순서로 정렬 =
K : ###### 6
A : ### 3
D : ## 2
Z : # 1
package com.test.memo;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class Practice2 {
public static void main(String[] args) throws Exception {
String[] data = { "A", "K", "A", "K", "D", "K", "A", "K", "K", "K", "Z", "D" };
HashMap<String, Integer> map = new HashMap<>();
// 각 문자의 등장 횟수를 세어 HashMap에 저장
for (String s : data) {
map.put(s, map.getOrDefault(s, 0) + 1);
}
// 값의 크기가 큰 순서대로 정렬 - HashMap은 정렬된 키의 컬렉션이 아니기 때문에 TreeMap으로 생성해 정렬해준다.
TreeMap<String, Integer> reverMap = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return map.get(o2).compareTo(map.get(o1));
}
});
reverMap.putAll(map);
// 기본 정렬 결과 출력
for (Map.Entry<String, Integer> ent : map.entrySet()) {
String key = ent.getKey();
String bar = "#".repeat(ent.getValue());
System.out.println(key + " : " + bar + " " + ent.getValue());
}
System.out.println();
// 크기가 순 순서대로 정렬
for (Map.Entry<String, Integer> ent : reverMap.entrySet()) {
String key = ent.getKey();
String bar = "#".repeat(ent.getValue());
System.out.println(key + " : " + bar + " " + ent.getValue());
}
}
}
for문으로 출력
package com.test.memo;
import java.util.Comparator;
import java.util.TreeMap;
public class Organize {
public static void main(String[] args) throws Exception {
String[] data = { "A", "K", "A", "K", "D", "K", "A", "K", "K", "K", "Z", "D" };
// TreeMap<String, Integer> map = new TreeMap<>(new Comparator<String>() {
//
// @Override
// public int compare(String o1, String o2) {
// return map.get(o2) - map.get(o1);
// } > 아직 map 이 정의도지 않았기떄문에 Comparator안에서 에러
// });
// @Override > 키값으로 내림차순 Z K D A
// public int compare(String o1, String o2) {
// return o2.compareTo(o1);
// }
TreeMap<String, Integer> map = new TreeMap<>();
for (String s : data) {
map.put(s, map.getOrDefault(s, 0) + 1);
}
TreeMap<String, Integer> revMap = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// return map.get(o2).compareTo(map.get(o1));이렇게도 가능
return map.get(o2) - map.get(o1);
}
});
revMap.putAll(map);
for (String key : map.keySet()) {
System.out.print(key + " : ");
for (int i = 0; i < map.get(key); i++) {
System.out.print("#");
}
System.out.println(" " + map.get(key));
}
System.out.println();
for (String key : revMap.keySet()) {
System.out.print(key + " : ");
for (int i = 0; i < revMap.get(key); i++) {
System.out.print("#");
}
System.out.println(" " + map.get(key));
}
}
}
서로 관련된 상수를 편하게 선언하기 위한 것으로, 상수를 여러개 정의해야 할 때 사용한다.
즉, 서로 연관된 상수들의 집합
모든 열거형은 java.lang.Enum<E> 클래스 를 상속하고, Object클래스를 상속받는다.(그러나 Object메소드 toString()만 오버라이딩 가능)
C언어에서는 enum클래스가 단순히 상수들의 집합으로 사용되지만, java에서는 타입까지 비교가 가능하다.
열거형은 주로 고정된 상수 집합을 정의할 떄 사용되며, 코드의 가독성과 유지보수성을 향상시킨다.
선언된 상수는 제일 왼쪽이나, 첫번째에 있는 상수부터 0번째 값을 가지고있다.
enum은 클래스 외부에도 선언할 수 있고, 클래스 내부에도 선언할 수 있다.
접근제어자 enum "enum클래스명"으로 선언하면 된다.
클래스 내부에서 선언
public class Cafe {
public enum Coffee { // Enum 클래스 선언
AMERICANO, //0번쨰
CAPPUCCINO, //1번째
CAFELATTE, //2번째
}
public static void main(String[] args) {
}
}
클래스 외부에서 선언
public enum Coffee { // Enum 클래스 선언
AMERICANO,
CAPPUCCINO,
CAFELATTE,
}
"enum 클래스명{ 상수 이름 }" 으로 객체를 생성할 수 있다. enum Scale {
DO, RE, MI, FA, SO, RA, TI
}
class SimpleEnum {
public static void main(String[] args) {
Scale sc = Scale.DO;
System.out.println(sc);
switch(sc) {
case DO:
System.out.println("도~ ");
break;
case RE:
System.out.println("레~ ");
break;
case MI:
System.out.println("미~ ");
break;
case FA:
System.out.println("파~ ");
break;
default:
System.out.println("솔~ 라~ 시~ ");
}
}
}
위 예제는 열거형 Scale의 정의다. Scale안에 위치한 이름들을 가리켜 '열거형 값' 이라 한다.(Enumerated Values)
기본적으로 '열거형 값'은 Scale.DO 와 같이 표현하지만 case문에서는 표현의 간결함을 위해 DO와 같이 '열거형 값'의 이름만 명시하기로 약속되어 있다.
enum Animal { DOG, CAT }
enum Person { MAN, WOMAN }
class SafeEnum {
public static void main(String[] args) {
System.out.println(Animal.DOG);
// 정상적인 메소드 호출
who(Person.MAN);
// 비정상적 메소드 호출
// who(Animal.DOG);
}
public static void who(Person man) {
switch(man) {
case MAN:
System.out.println("남성 손님입니다.");
break;
case WOMAN:
System.out.println("여성 손님입니다.");
break;
}
}
}
public class Cafe {
public enum Coffee {
AMERICANO,
CAPPUCCINO,
CAFELATTE,
}
public int getCoffeeValue(Coffee type) { //Enum 상수를 매개변수로 받음
switch(type) {
case AMERICANO:
return 1500;
case CAPPUCCINO:
return 2300;
case CAFELATTE:
return 2000;
default:
return 0;
}
}
public static void main(String[] args) {
Cafe sample = new Cafe();
System.out.println(sample.getCoffeeValue(Coffee.AMERICANO));
//만약 변수로 선언하고싶다면 Coffee TypeOfCoffee = Coffee.AMERICANO; 이렇게 선언해서 괄호 안에 TypeOfCoffee를 넣으면 된다..
}
}
enum 상수에 값을 지정함으로써 보다 간결하게 만들 수 있다.
public class Cafe {
public enum Coffee {// 객체를 생성하면 컴파일러에서 자동으로 생성자를 실행해, 값을 생성자에 저장하고 getValue()를 실행하면 해당 값이 리턴되는 것이다.
AMERICANO(1500),
CAPPUCCINO(2300),
CAFELATTE(2000);
private final int value;
Coffee(int i) { //enum 생성자
this.value = i;
}
public int getValue() { //enum상수 값을 불러오기 위한 메소드
return value;
}
}
public static void main(String[] args) {
System.out.println(Coffee.AMERICANO.getValue());
// 1500 출력
}
}
값을 지정하기 위해선 소괄호() 안에 값을 적어주면 된다.
값을 지정하기 위해 반드시 생성자가 존재해야한다. > enum객체 생성 시 객체에 값을 저장하기 위한 용도로 사용된다.
접근제어자는 private, pacakage-private만 가능)
상수에 여러 값 저장 가능
public enum Coffee {
AMERICANO(1500, true, "Y"),
CAPPUCCINO(2300, true, "Y"),
CAFELATTE(2000, false, "N");
private final int value;
private final boolean discount;
private final String count;
Coffee(int value, boolean discount, String count) {
this.value = value;
this.discount = discount;
this.count = count;
}
public int getValue() {
return value;
}
public boolean getDiscount() {
return discount;
}
public String getCount() {
return count;
}
}
toString() 예제1
package com.test.memo;
class Customer {
enum Gender {
MALE, FEMALE
}
private String name;
private Gender gen;
Customer(String n, String g) {
name = n;
if (g.equals("man"))
gen = Gender.MALE;
else
gen = Gender.FEMALE;
}
@Override
public String toString() {
if (gen == Gender.MALE)
return "Thank you, Mr " + name;
else
return "Thank you, Mrs " + name;
}
}
public class Organize {
public static void main(String[] args) {
Customer cus1 = new Customer("Brown", "man");
Customer cus2 = new Customer("Susan Hill", "woman");
System.out.println(cus1);
System.out.println(cus2);
}
}
//Thank you, Mr Brown
//Thank you, Mrs Susan Hill
toString() 예제2 일반 클래스로(열거형을 생성하는 과정 모방) > 잘못된 예제
package com.test.memo;
class Person {
public static final Person MAN = new Person();//열거형 값의 실체를 설명하는 문장
public static final Person WOMAN = new Person(); //생성자가 private이라 직접호출 불가
@Override
public String toString() {
return "I am a dog person";
}
}
public class Organize {
public static void main(String[] args) {
System.out.println(Person.MAN); //I am a dog person
System.out.println(Person.WOMAN); //I am a dog person
}
}
위와같이 열거형 상수를 생성자를 통해 생성하는 것은 열거형의 의도와 맞지않다.
열거형을 정의할 때는 열거형 상수만을 열거형의 선언으로 사용해야한다.
java컴파일러는 열거형 구조를 강제하지 않기때문에 위와같은 구조가 컴파일은 된다.
위 예제는 일반 클래스를 사용해 비슷한 동작을 구현했기에 컴파일이 됐지만 만약 class Person을 enum Person으로 했다면 컴파일 오류가 발생한다.
예제 2를 enum클래스로 > 맞는 예제
enum Person {
MAN, WOMAN;
@Override
public String toString() {
return "I am a dog person";
}
}
class EnumConst {
public static void main(String[] args) {
System.out.println(Person.MAN);
System.out.println(Person.WOMAN);
}
}
두 열거형값은 Person 인스턴스를 참조하는 참조변수이다. 이에 대한 증거로 예제에서는System.out.println(Person.MAN);문장을 통해 toString 메소드가 호출되었음을 보이고 있다.
열거형 정의에도 생성자가 없으면 디폴트 생성자가 삽입된다. 다만 생성자는 private으로 선언되어 직접 인스턴스를 생성하는 것이 불가능해진다.
enum 클래스의 메소드

compareTo(E e): 이 메서드는 열거형 상수의 순서를 비교하는 데 사용된다. E는 해당 열거형 클래스를 가리키는 타입 매개변수다. 두 열거형 상수 사이의 순서 차이를 나타내는 정수를 반환한다.
getDeclaringClass(): 이 메서드는 해당 열거형 상수가 속한 클래스의 Class 객체를 반환한다.
name(): 이 메서드는 해당 열거형 상수의 이름을 문자열로 반환다.
ordinal(): 이 메서드는 해당 열거형 상수의 순서(0부터 시작)를 반환한다.
valueOf():이 메서드는 해당 문자열과 일치하는 열거형 상수를 반환하는 열거형 클래스에서 자동으로 생성되는 메서드로, 대부분의 경우 상수 이름을 기반으로 열거형 상수를 찾아 반환한다.
이 메서드는 static메서드로, enum클래스에서 상속받는 메서드는 아니다.
compareTo()
Enum은 선언된 순서대로 상수들의 순서가 정해진다. compareTo 메소드는 이 상수의 순서 차이를 리턴한다. 같은 상수라면 '0', 호출한 객체의 상수가 매개변수로 받은 상수보다 앞에있다면 음수(-)를 뒤에 있다면 양수를(+) 리턴한다.
public class Cafe {
public enum Coffee {
AMERICANO(1500),
CAPPUCCINO(2300),
CAFELATTE(2000);
private final int value;
Coffee(int i) {
this.value = i;
}
public int getValue() {
return value;
}
}
public static void main(String[] args) {
Coffee Cof1 = Coffee.AMERICANO;
Coffee Cof3 = Coffee.CAFELATTE;
System.out.println(Cof1.compareTo(Cof3));
// -2 출력
}
}
ordinal()
Enum 객체 상수의 순서를 리턴한다. 배열과 같이 첫번째 상수는 0부터 시작하여 1씩 커진다.
public class Cafe {
public enum Coffee {
AMERICANO(1500),
CAPPUCCINO(2300),
CAFELATTE(2000);
private final int value;
Coffee(int i) {
this.value = i;
}
public int getValue() {
return value;
}
}
public static void main(String[] args) {
Coffee Cof1 = Coffee.AMERICANO;
Coffee Cof3 = Coffee.CAFELATTE;
System.out.println(Cof1.ordinal());
// 0 출력
System.out.println(Cof3.ordinal());
// 2 출력
}
}
name
Enum 객체 상수를 리턴한다.
public static void main(String[] args) {
Coffee Cof1 = Coffee.AMERICANO;
System.out.println(Cof1.name());
// AMERICANO 출력
}
value
Enum에 선언된 모든 상수를 Enum 자료형의 배열로 리턴한다.
public static void main(String[] args) {
Coffee [] CofffeeArray = Coffee.values();
for(Coffee cof: CofffeeArray) {
System.out.print(cof+" ");
// AMERICANO CAPPUCCINO CAFELATTE 출력
}
}
enum에 정의도니 상수들은 enum타입의 객체다. > 단순 정수 값이 아닌 해당 enum타입 객체다.
생성자와 메소드등을 추가할 수 있다.
enum은 다른 클래스와 비슷한 구조를 가져서 필드, 생성자, 메서드를 포함할 수 있다.
인터페이스(Interface): 열거형은 인터페이스를 구현할 수 있다. 이를 통해 열거형이 특정 인터페이스를 준수하도록 할 수 있습니다.
메서드(Method): 열거형은 메서드를 가질 수 있다. 이를 통해 각 열거형 상수에 대해 특정 동작을 정의할 수 있다.
Static 및 Final: 열거형의 필드는 기본적으로 public static final로 정의된다. 즉, 상수다. 또한 열거형의 메서드나 내부 클래스는 static으로 선언될 수 있다.
제약 사항
상속(Inheritance): 열거형은 다른 클래스를 상속할 수 없다. Java는 단일 상속만을 지원하며 열거형은 이미 Enum 클래스를 상속하고 있기 때문에 다른 클래스를 상속할 수 없다.
인스턴스 생성(Instance Creation): 열거형의 인스턴스는 개발자가 직접 생성할 수 없다. 열거형 상수는 정의된 열거형 타입의 유일한 인스턴스이기 때문에 컴파일러가 자동으로 생성한다.
interface Scale {
int DO = 0; int RE = 1;
int MI = 2; int FA = 3;
int SO = 4; int RA = 5;
int TI = 6;
}
class InterfaceBaseConst {
public static void main(String[] args) {
int sc = Scale.DO;
switch(sc) {
case Scale.DO:
System.out.println("도~ ");
break;
case Scale.RE:
System.out.println("레~ ");
break;
case Scale.MI:
System.out.println("미~ ");
break;
case Scale.FA:
System.out.println("파~ ");
break;
default:
System.out.println("솔~ 라~ 시~ ");
}
}
}
열거형 메서드를 추가한 예제
interface AnimalSound {
String makeSound();
}
enum Animal implements AnimalSound {
DOG("Woof"),
CAT("Meow"),
COW("Moo");
private final String sound;
Animal(String sound) {
this.sound = sound;
}
@Override
public String makeSound() {
return sound;
}
}
public class Main {
public static void main(String[] args) {
for (Animal animal : Animal.values()) {
System.out.println(animal + " makes " + animal.makeSound());
}
}
}
매개변수의 개수를 동적으로 지정하는 기능 > 컬렉션이나 배열을 사용한것과 비슷
타입 ... 변수명 의 형식으로 선언한다.class Varargs {
public static void showAll(String... vargs) {
System.out.println("LEN: " + vargs.length);//length를 호출해 길이 확인
for(String s : vargs)
System.out.print(s + '\t');
System.out.println();
}
/* 가변인자가 이렇게 처리하는 방식인것
public static void showAll(String[] vargs) {...}
public static void main(String[] args){
showAll(new String[]{"Box"});
showAll(new String[]{"Box", "Toy"});
showAll(new String[]{"Box", "Toy", "Apple"});
}
*/
public static void main(String[] args) {
showAll("Box");
showAll("Box", "Toy");
showAll("Box", "Toy", "Apple"); //이렇게 전달되면 가변인자에서 배열을 생성해 전달되는 인자를 담는다.(vargs에)
}
}
/*
실행결과
LEN: 1
Box
LEN: 2
Box Toy
LEN: 3
Box Toy Apple
*/
가변인자 오버로딩시 주의점
public class Main {
public static void main(String[] args) {
String[] strArr = {"100", "200", "300"};
System.out.println(concatenate("", "100", "200", "300")); // 에러 발생
System.out.println(concatenate("_", strArr));
System.out.println(concatenate(",", new String[] {"1", "2", "3"}));
System.out.println(concatenate(",", new String[0]));
}
static String concatenate(String... args) {
return concatenate("", args);
}
static String concatenate(String delim, String... args) {
String result = "";
for(String str : args) {
result += str + delim;
}
return result;
}
}
concatenate메서드는 매개변수로 입력된 문자열에 구분자를 사이에 포함시켜 결갑해서 반환한다.
가변인자로 매개변수를 선언했기 때문에 문자열을 개수의 제약없이 매개변수로 지정할 수 있다.
String[] strArr = {"100", "200", "300"};System.out.println(concatenate("-", strArr));System.out.println(concatenate("-", new String[] {"100", "200", "300"}));
System.out.println(concatenate("-", {"100", "200", "300"}));System.out.println(concatenate("-", "100", "200", "300"));에러 내용
java: reference to concatenate is ambiguous
both method concatenate(java.lang.String...) in Main and method concatenate(java.lang.String,java.lang.String...) in Main match
에러의 내용을 살펴보면 두 오버로딩된 메서드가 구분되지 않아서 발생하는 것임을 알 수 있다. 가변인자를 선언한 메서드를 오버로딩하면, 메서드를 호출했을 때 이와 같이 구별되지 못하는 경우가 발생하기 쉽기 때문에 주의해야 한다. 가능하면 가변인자를 사용한 메서드는 오버로딩 하지 않는 것이 좋다.
다른 프로그램에서 유용한 정보를 제공하기 위해 사용되는 것으로 주석과 같은 의미를 가진다.
어노테이션의 역할
어노테이션의 종류
자바에서 기본적으로 제공하는 어노테이션이다.
@Override
컴파일러에게 메서드를 오버라이딩하는 것이라고 알린다.
@Deprecated
앞으로 사용하지 않을 대상임을 알린다.
@FunctionalInterface
함수형 인터페이스라는 것을 알린다.
@SuppressWarning
컴파일러가 경고 메시지를 나타내지 않는다.
@SafeVaragrs
제네릭과 같은 가변 인자의 매개변수를 사용할 때의 경고를 나타내지 않는다.
메타 어노테이션
어노테이션에 붙이는 어노테이션으로, 어노테이션을 정의하는 데 사용한다.
@Target
어노테이션을 정의할 때 적용 대상을 지정하는 데 사용한다.
@Documented
어노테이션 정보를 javadoc으로 작성된 문서에 포함시킨다.
@Inherited
어노테이션이 하위 클래스에 상속되도록 한다.
@Retention
어노테이션이 유지되는 기간을 정하기 위해 사용한다.
@Repeatable
어노테이션을 반복해서 적용할 수 있도록 한다.
사용자 정의 어노테이션
사용자가 직접 정의하여 사용하는 어노테이션이다.
람다식(Lambda expression)은 간단히 말해서 메서드를 하나의 '식(expression)'으로 표현한 것이다. 메서드를 람다식으로 표현하면 메서드의 이름과 반환값이 없어지므로, 람다식을 '익명 함수(anonymous function)'이라고도 한다.
장점
단점
람다식은 함수적 인터페이스인 경우에만 사용이 가능하다.
인터페이스를 구현하는 방식은 여러가지가 있다.
public class Main {
public static void main(String[] args) {
//2. 익명함수로 메인 클래스 내에서 구현하여 호출
MaxNumber maxNumber = new MaxNumber() {
@Override
public int getMaxNumber(int x, int y) {
return x >= y ? x : y;
}
};
System.out.println(maxNumber.getMaxNumber(3,1));
}
}
MaxNumber Interface를 직접 메인 메소드 내에서 구현하여 호출한 방식이다.
똑같이 출력 결과가 3임을 알 수 있다.
public class Main {
public static void main(String[] args) {
//3. 람다식을 이용하여 호출 방식
MaxNumber maxNumber = (x, y) -> x >= y ? x : y;
System.out.println(maxNumber.getMaxNumber(3,1));
}
}//3
MaxNumber maxNumber = (str) → {System.out.println(str);};MaxNumber maxNumber = str → {System.out.println(str);};MaxNumber maxNumber = (str) → System.out.println(str);MaxNumber maxNumber = (str) → { return String.valueOf(str);};MaxNumber maxNumber = (str) → String.valueOf(str);MaxNumber maxNumber = () → System.out.println("매개변수 없음");int[] arr = new int[5];
Arrays.setAll(arr, ()->(int)(Math.random()*5+1)); // arr=[1,5,2,1,1]
//위의 람다식을 메서드로 표현하면 다음과 같다.
int method() {
return (int)(Math.random()*5 + 1;
}
5개 배열을 선언했으니, 각 인덱스 요소마다 위 람다식이 실행되고, 람다식이 리턴한 값으로 요소가 채워진다.
람다식을 메서드로 표현한것이 아래
람다식을 인수로도 넣을 수 있고, 리턴값으로도 가능하다.(변수처럼 다룰 수 있음)
해당하는 함수형 인터페이스를 직접 명시해야한다.
Comparable인터페이스를 사용하려면 Comparable을 구현하는 클래스가 있어야한다. 그 후에 해당 클래스의 객체를 사용하여 람다식을 통해 정렬 수행을 할 수 있는 것이다.
반드시 추상 메서드는 한개만 존재해야 람다를 사용할수있다,
import java.util.*;
class MyObject implements Comparable<MyObject> {
private int value;
public MyObject(int value) {
this.value = value;
}
public int getValue() {
return value;
}
@Override
public int compareTo(MyObject other) {
return this.value - other.value;
}
}
public class Main {
public static void main(String[] args) {
List<MyObject> list = new ArrayList<>();
list.add(new MyObject(3));
list.add(new MyObject(1));
list.add(new MyObject(2));
Collections.sort(list, (obj1, obj2) -> obj1.compareTo(obj2));
for (MyObject obj : list) {
System.out.println(obj.getValue());
}
}
}
람다식 예제 1
//메서드
int max(int a, int b) {
return a > b ? a : b;
}
//람다식
(1)
(int a, int b) -> { return a > b ? a : b?; }//한문장이면 중괄호 생략가능 > return도 반드시 생략
(2)
(int a, int b) -> a > b ? a : b//자료형도 생략 가
(3)
(a, b) -> a > b? a : b //이 형태를 제일 많이 씀
람다식이 한문장이면 중괄호 생략이 가능하고, return도 생략하고, 세미콜론도 생략해야한다.(위는 중괄호가 있어서 )
자료형 생략이 가능하다.
람다식 예제 2
//메서드
void printVar(String name, int i) {
System.out.println(name + "=" + i);
}
//람다식
(1)
(String name, int i) -> { System.out.println(name + "=" + i); }
(2)
(name, i) -> { System.out.println(name + "=" + i); }//자료형을 생략할 수 있기 때문에 생략한 형태
(3)
(name,i) -> System.out.println(name + "=" + i)//중괄호 생략 가능
람다식 예제 3
//메서드
int square(int x) {
return x * x;
}
//람다식
(1)
(int x) -> x* x
(2)
(x) -> x * x
(3)
x -> x * x //인수가 하나면 소괄호 생략이 가능하다.
package com.test.memo;
interface Printable {
void print();
}
class Papers {
private String con;
public Papers(String s) {
con = s;
}
public Printable getPrinter() {
return new Printable() {
@Override
public void print() {
System.out.println(con);
}
};
}
}
public class Practice {
public static void main(String[] args) {
Papers p = new Papers("서류 내용: 행복합니다.");
Printable prn = p.getPrinter();
prn.print();
}
}
package com.test.memo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Practice {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("ROBOT");
list.add("APPLE");
list.add("BOX");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}); // 정렬
System.out.println(list);
}
}
package com.test.memo;
interface Printable {
void print(String s);
}
public class Practice {
public static void main(String[] args) {
Printable prn = new Printable() {
@Override
public void print(String s) {
System.out.println(s);
}
};
prn.print("What is Lambda?");
}
}
interface Printable {
void print(String s);
}
class Lambda3 {
public static void main(String[] args) {
Printable prn = (s) -> { System.out.println(s); };
prn.print("What is Lambda?");
}
}
/*
What is Lambda?
*/
interface Printable {
void print(String s);
}
class Lambda4 {
public static void ShowString(Printable p, String s) {
p.print(s);
}
public static void main(String[] args) {
ShowString(/* 코드 완성 */);
}
}
/*
출력 결과가 다음과 같이 나오도록
ShowString에 적절한 인자를 전달하시오.
What is Lambda?
*/
1번
interface Printable {
void print(String s);
}
class Lambda4 {
public static void ShowString(Printable p, String s) {
p.print(s);
}
public static void main(String[] args) {
ShowString((s) -> { System.out.println(s); }, "What is Lambda?");
}
}
/*
What is Lambda?
*/
2번
interface Printable {
void print(String s);
}
class Lambda4 {
public static void ShowString(Printable p, String s) {
p.print(s);
}
public static void main(String[] args) {
ShowString((s) -> { System.out.println(s); }, "What is Lambda?");
}
}
/*
What is Lambda?
*/
interface MyFunction{
int max(int a, int b);
}
public class LambdaTest {
public static void main(String[] args) {
MyFunction f = new MyFunction() {
public int max(int a, int b) {
return a > b ? a : b;
}
};
int big = f.max(5, 3); // 익명 객체의 메소드 호출
System.out.println(big);
}
}
람다식으로 변경
package com.test.memo;
interface MyFunction {
int max(int a, int b);
}
public class Practice {
public static void main(String[] args) {
MyFunction f = (a, b) -> a > b ? a : b;
int big = f.max(5, 3); // 익명 객체의 메소드 호출
System.out.println(big);
}
}
interface MyFunction2{
void printVar(String name, int i);
}
public class LambdaTest2 {
public static void main(String[] args) {
MyFunction2 f = new MyFunction2() {
public void printVar(String name, int i) {
System.out.println(name + "=" + i);
}
};
f.printVar("Hong", 100); // 익명 객체의 메소드 호출
}
}
람다식으로 변경
package com.test.memo;
interface MyFunction2 {
void printVar(String name, int i);
}
public class Practice {
public static void main(String[] args) {
MyFunction2 f = (name, i) -> System.out.println(name + "=" + i);
f.printVar("Hong", 100); // 익명 객체의 메소드 호출
}
}
interface MyFunction3{
int square(int x);
}
public class LambdaTest3 {
public static void main(String[] args) {
MyFunction3 f = new MyFunction3() {
public int square(int x) {
return x * x;
}
};
int num = f.square(5); // 익명 객체의 메소드 호출
System.out.println(num);
}
}
람다식
package com.test.memo;
interface MyFunction3 {
int square(int x);
}
public class Practice {
public static void main(String[] args) {
MyFunction3 f = x -> x * x;
int num = f.square(5); // 익명 객체의 메소드 호출
System.out.println(num);
}
}
interface MyFunction4{
int roll();
}
public class LambdaTest4 {
public static void main(String[] args) {
MyFunction4 f = new MyFunction4() {
public int roll() {
return (int) (Math.random() * 6);
}
};
int num = f.roll(); // 익명 객체의 메소드 호출
System.out.println(num);
}
}
람다식
package com.test.memo;
interface MyFunction4 {
int roll();
}
public class Practice {
public static void main(String[] args) {
MyFunction4 f = () -> (int) (Math.random() * 6);
int num = f.roll(); // 익명 객체의 메소드 호출
System.out.println(num);
}
}
interface MyFunction5{
int sumArr(int[] arr);
}
public class LambdaTest5 {
public static void main(String[] args) {
MyFunction5 f = new MyFunction5() {
public int sumArr(int[] arr) {
int sum = 0;
for(int i : arr)
sum += i;
return sum;
}
};
int num = f.sumArr(new int[] {1,2,3,4,5}); // 익명 객체의 메소드 호출
System.out.println(num);
}
}
람다식
package com.test.memo;
interface MyFunction5 {
int sumArr(int[] arr);
}
public class Practice {
public static void main(String[] args) {
MyFunction5 f = arr -> {
int sum = 0;
for (int i : arr)
sum += i;
return sum;
};
int num = f.sumArr(new int[] { 1, 2, 3, 4, 5 }); // 익명 객체의 메소드 호출
System.out.println(num);
}
}
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class LambdaTest6 {
public static void main(String[] args) {
List<String> list = Arrays.asList("abc", "aaa", "bbb", "ccc");
Collections.sort(list, new Comparator<String>() {
public int compare(String s1, String s2) {
return s2.compareTo(s1);
}
});
System.out.println(list);
}
}
람다식
package com.test.memo;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Practice {
public static void main(String[] args) {
List<String> list = Arrays.asList("abc", "aaa", "bbb", "ccc");
Collections.sort(list, (s1, s2) -> s2.compareTo(s1));//내림차순
System.out.println(list);
}
}
파일 입출력 메소드는 입력과 출력을 표준 입출력 장치가 아닌 파일로 처리하는 메소드다.

1단계 : 파일 열기
읽기용 : FileInputStream 변수명 = new FileInputStream("파일명");
쓰기용 : FileOutputStream 변수명 = new FileOuputStream("파일명");
2단계 : 파일 처리
3단계 : 파일 닫기
스트림은 데이터를 송수신하기 위한 통로의 개념으로서 입력 혹은 출력, 한쪽 방향으로만 진행된다.
특징
FIFO구조다.(컬렉션에서 큐와 동일)
스트림은 단방향이다.
스트림은 지연될 수 있다.
넣어진 데이터가 처리되기 전까지는 스트림에 사용되는 스레드는 지연 상태에 빠진다.
스트림의 분류
1. 전송 방향에 의한 분류
입력 스트림 : 디바이스로부터 데이터를 읽어오는 스트림
출력 스트림 : 디바이스로 데이터를 출력하는 스트림
2. 전송 단위에 의한 분류
바이트스트림 : 1 Byte 단위로 입력, 출력하는 스트림
문자스트림 : 한 문자(2Byte) 단위로 입력, 출력하는 스트림
바이트 스트림은 데이터를 바이트(Byte)단위로 처리한다. > 1byte(영어, 특수기호)
InputStream 및 OutputStream 클래스와 그 하위 클래스들이 이에 해당한다.
FileInputStream은 예외처리가 꼭 필요하다.
main문에 throw Exception을 추가하거나, try catch문으로 IOException으로 예외처리를 해줘야 한다.
문자 스트림은 문자(char)단위로 데이터를 처리한다. > 2 byte(한글)
문자 데이터를 읽고 쓰는 데 사용되며, 문자의 인코딩 및 디코딩을 자동으로 처리한다.
텍스트 파일, 문자열, 문자열 표준 입력 및 출력 등에 사용된다.
Reader 및 Writer 클래스와 그 하위 클래스들이 이에 해당된다.
fileWriter예제
package com.test.memo;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Practice1 {
public static void main(String[] args) throws Exception {
try (Writer out = new FileWriter("hyper.txt", true)) {
out.write(65);
out.write(66);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

파일 시스템의 파일에 대한 경로명을 추상화한 클래스
File클래스는 파일 시스템의 파일에 대한 경로명을 추상화한 클래스다.
File 또는 dir의 경로를 나타내고, 속성을 읽고 변경할 수 있는 메서드를 제공한다.
파일이나 디렉토리를 생성, 삭제, 이름 변경 등의 작업을 수행할 때 사용된다.
주로 파일이나 디렉토리의 존재 여부를 확인하거나 파일의 속성(크기, 수정 일자 등)을 가져오는 데 사용된다.
파일 내용의 읽기 및 쓰기에 직접적으로 관여하지 않는다.

Buffered 클래스들은 입출력 작업에서 버퍼링을 제공하여 입출력 효율을 높이는 데 사용된다. > 입출력 스트림이나 read() , writer()와 함께 사용된다.따라서,
File클래스는 파일 시스템의 파일을 다루는 데 사용되고,Buffered클래스들은 입출력 작업에서 버퍼링을 통해 성능을 향상시키는 데 사용된다.종종 함께 사용되어 파일에 대한 입출력 작업을 수행하는 데 효율적으로 활용된다.
예제 1 - 파일 복사,개념
package com.test.memo;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Practice {
public static void main(String[] args) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter("org.txt"))) {
writer.write("This is a new file created by Java program."); // 파일에 데이터 쓰기
} catch (IOException e) {
e.printStackTrace();
}
InputStream in = new FileInputStream("org.txt");
OutputStream out = new FileOutputStream("cpy.txt");
int copyByte = 0;
int bData;
while (true) {
bData = in.read();
if (bData == -1)
break;
out.write(bData);
copyByte++;//1바이트씩 읽어들이는
}
if(in != null) in.close();
if(out != null) out.close(); //안전성 up
System.out.println("복사된 바이트 크기 " + copyByte);
}
}//복사된 바이트 크기 43
위 예제처럼 코드를 짜지 않는다. 예외처리를 하지 않겠다고 메인메서드에서 던져주고있기 때문

예제 2 filterOut
필터 입력 스트림 클래스 - (FilterInputStream) 클래스를 상속한다.
필터 출력 스트림 클래스 - (FilterOutputStream) 클래스를 상속한다.
FilterInputStream 클래스와 FilterOutputStream 클래스도 각각 InputStream과 OutputStream을 상속하나, 최상위 클래스는 아니다.
import java.io.*;
class DataBufferFilterStream
{
public static void main(String[] args) throws IOException
{
OutputStream out=new FileOutputStream("data.bin");//순서 중요
BufferedOutputStream bufFilterOut=new BufferedOutputStream(out);
DataOutputStream dataFilterOut=new DataOutputStream(bufFilterOut);
dataFilterOut.writeInt(275);//4바이트 275로 읽어들임
dataFilterOut.writeDouble(45.79);//8바이트 45.79로 읽어들임
dataFilterOut.close();
InputStream in=new FileInputStream("data.bin");
BufferedInputStream bufFilterIn=new BufferedInputStream(in);
DataInputStream dataFilterIn=new DataInputStream(bufFilterIn);
int num1=dataFilterIn.readInt();
double num2=dataFilterIn.readDouble();
dataFilterIn.close();
System.out.println(num1);//275 출력
System.out.println(num2);//45.79 출력
}
}
BufferedOutputStream은 데이터를 일정한 크기의 버퍼에 임시로 저장한 후에 한 번에 파일에 쓰기 때문에 파일 입출력 횟수가 줄어들어 성능이 향상될 수 있습니다.I/O 모델의 핵심은 스트림을 이해하는데 있다. 본디 스트림이란 ( ), 또는 ( )를 의미한다.
public abstract int read() throws IOException : 입력 스트림으로 부터 1 바이트를 읽어들인다. 읽은 바이트를 반환하며, 파일의 끝에 도달하면 -1을 반환한다.public void close() throws IOException : 입력 스트림을 닫는다. 자원을 해제하고 연결된 파일이나 네트워크 등을 종료한다.InputStream <> OutputStream
FileInputStream <> FileOutputStream
InputStream에 대응하는 클래스는 OutputStream이다. 즉 OutputStream은 모든 출력 스트림이 상속하는 최상위 클래스이다. 그리고 FileOutputStream은 이를 상속하는 클래스이다.
public abstract void write (int b) throws IOException
public void close() throws IOException
package com.test.memo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Practice {
public static void main(String[] args) {
int r = 0;
int cnt = 0;
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream("Hi.txt");
out = new FileOutputStream("HiCpy.txt");
while ((r = in.read()) != -1) {
cnt++;
out.write(r);
}
System.out.println("복사된 byte는 " + cnt);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {//이렇게 명시적으로 close()메서드를 호출하는 것은 예전 방법 아래 예제가 더 효율적
try {
if (in != null)
in.close();
if (out != null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
try-with-resources문을 이용 - 더 효율적
괄호()안에 객체를 생성하는 문장을 넣으면, 이 객체는 따로 close()를 호출하지 않아도 try블럭을 벗어나는 순간 자동적으로 close()가 호출된다.
package com.test.memo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Practice {
public static void main(String[] args) {
int r = 0;
int cnt = 0;
// InputStream in = null;
// OutputStream out = null;
try (FileInputStream in = new FileInputStream("Hi.txt"); // 데이터를 읽어온다.
FileOutputStream out = new FileOutputStream("Hicpy.txt")) { // 데이터를 쓴다.
while ((r = in.read()) != -1) { // 파일의 끝에 도달하면 -1을 반환한다 그래서 그 전까지 반복문
cnt++; // 몇바이트를 가져왔는지 센다.
out.write(r); // 읽어온 바이트를 Hicpy에 쓴다.
} // 파일 복사가 완료되면 try-with-resources구문이 자동으로 리소스를 닫는다.
System.out.println("복사된 byte는 " + cnt);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// } finally {
// try {
// if (in != null)
// in.close();
// if (out != null)
// out.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}
}
FileInputStream은 InputStream클래스를 상속받는 클래스다. 따라서 직접 사용할 수 있지만, 보통은 특정 유형의 스트림을 명시적으로 사용하는 것이 코드의 가독성을 높인다.FileInputStream은 파일로부터 데이터를 바이트 스트림으로 읽어오는 클래스다. > 문자 스트림도 존재 int read(byte[] b) throws IOException
메소드의 인자로 byte형 배열의 참조를 전달 > 입력 스트림을 통해 읽어 들여진 데이터들이 배열에 저장
그리고 위 메소드는 실제 읽어 들인 데이터의 크기 반환더 이상 읽을 데이터가 존재하지 않으면 -1 반환
public void write(byte[] b, int off, int len) throws IOExceptionimport java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyTest2 {
public static void main(String[] args) {
byte[] r = new byte[1024];//1k가 1024byte
int len = 0, total = 0;
try(FileInputStream in = new FileInputStream("Grit.txt");
FileOutputStream out = new FileOutputStream("GritCopy.txt")) {
while( (len = in.read(r)) != -1)//읽어온 바이트 수 저장
{
total += len; //쓰여진 총 바이트 수
out.write(r, 0, len);//r에 0부터 len까지 복
}
System.out.println(total + "바이트 배열 단위 파일 복사가 완료되었습니다.");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
배열의 크기만큼 데이터를 읽어와 배열에 저장하고, 실제로 읽어온 바이트 수를 반환 > 잃어온 데이터의 수는 len에 저장된다.
read()메서드가 읽어온 바이트 수가 데이터의 실제 길이를 나타내는 것이다. > 이를 통해 배열에 저장된 데이터의 범위를 지정한다.
BufferedInputStream 버퍼 필터 입력 스트림
BufferedOutputStream 버퍼 필터 출력 스트림
필터 입력 스트림 입력 스트림에 연결하는 필터 스트림
필터 출력 스트림 출력 스트림에 연결하는 필터 스트림
package com.test.memo;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Practice {
public static void main(String[] args) {
try (OutputStream out = new FileOutputStream("data.bin");
DataOutputStream filterOut = new DataOutputStream(out)) {
filterOut.writeInt(275);//파일에 275를 기록
filterOut.writeDouble(45.79);//파일에 기록 > 바이트 형식으로 > 파일에 쓰기 전에는 바이트 배열에 임시로 저장되어있다.
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try (InputStream in = new FileInputStream("data.bin"); DataInputStream filterIn = new DataInputStream(in)) {
//각각의 파일로부터 정수와 실수를 읽어온다.
//파일에서 데이터를 읽어오면 해당하는 바이트 수를 해당하는 자료형으로 변환해 변수에 저장(이진 형식으로)
int num1 = filterIn.readInt(); //이진 형식으로 저장된 값을 해당 자료형 형식으로 변환해 반환
double num2 = filterIn.readDouble();
System.out.println(num1);
System.out.println(num2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}//275 45.79출력
OutputStream은 바이트 단위로 데이터를 출력하는 스트림을 나타내는 추상 클래스다.
FileOutputStream은 파일에 바이트 단위로 데이터를 출력하는 클래스입니다.
DataOutputStream은 다양한 데이터 유형을 바이트 단위로 출력할 수 있는 스트림 클래스입니다.
"data.bin"이라는 파일에 데이터를 출력하기 위해
FileOutputStream을 생성하고, 이를DataOutputStream으로 감싸 데이터를 출력해준다.try-with-resources구문을 사용하여 자원을 자동으로 닫아줍니다.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class JavaIO18 {
public static void main(String[] args) {
String inFileName = "Grit.txt";
String outFileName = "cpy.txt";
int readByte = 0;
int byteCnt = 0;
try(FileInputStream in = new FileInputStream(inFileName);
BufferedInputStream bIn = new BufferedInputStream(in);
FileOutputStream out = new FileOutputStream(outFileName);
BufferedOutputStream bOut = new BufferedOutputStream(out))
{
while( (readByte=bIn.read()) != -1)
{
bOut.write(readByte);
byteCnt++;
}
System.out.println(byteCnt+ "byte의 파일 복사가 완료되었습니다.");
}
catch(FileNotFoundException e)
{
System.out.println("파일이 존재하지 않습니다.");
e.printStackTrace();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
BufferedInputStream 데이터를 읽어 들이는 메소드 두개는?
public int read() throws IOException
public int read(byte[] b, int off, int len) throws IOException
데이터의 중요도가 높거나, 버퍼가 꽉차지 않아도 출력 스트림을 통해서 파일에 저장해야 할 데이터가 존재한다면 다음의 메소드를 호출해야 한다.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class JavaIO21 {
public static void main(String[] args) {
String fileName="fbdTest.txt";
try(FileOutputStream out = new FileOutputStream(fileName);
BufferedOutputStream bOut = new BufferedOutputStream(out);
DataOutputStream dataOut = new DataOutputStream(bOut))
{
dataOut.writeInt(275);
dataOut.writeDouble(45.79);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try(FileInputStream in = new FileInputStream(fileName);
BufferedInputStream bIn = new BufferedInputStream(in);
DataInputStream dataIn = new DataInputStream(bIn))
{
int intData = 0;
double dblData = 0;
intData = dataIn.readInt();
dblData = dataIn.readDouble();
System.out.println(intData + " " + dblData);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
class DataBufferedFilterPerformance
{
public static void performanceTest(DataOutputStream dataOut)
throws IOException
{
long startTime=System.currentTimeMillis();
for(int i=0; i<10000; i++)
for(int j=0; j<10000; j++)
dataOut.writeDouble(12.345);
dataOut.flush();
long endTime=System.currentTimeMillis();
System.out.println("경과시간: "+ (endTime-startTime));
}
public static void main(String[] args) throws IOException
{
OutputStream out1=new FileOutputStream("data1.bin");
DataOutputStream dataOut=new DataOutputStream(out1);
performanceTest(dataOut);
dataOut.close();
OutputStream out2=new FileOutputStream("data2.bin");
BufferedOutputStream bufFilterOut
=new BufferedOutputStream(out2, 1024*10);
DataOutputStream dataBufOut=new DataOutputStream(bufFilterOut);
performanceTest(dataBufOut);
dataBufOut.close();
}
}