MY MEMO

[JAVA] 기본 개념 다지기 - 2 본문

STUDYING/JAVA

[JAVA] 기본 개념 다지기 - 2

l_j_yeon 2017. 10. 16. 01:56

출처 : https://programmers.co.kr/learn/courses/9


method chaining

자기 자신을 리턴하여 계속해서 자신의 메소드를 호출하는 방식


StringBuffer sb2 = new StringBuffer();

StringBuffer sb3 = sb2.append("hello");

if(sb2 == sb3) System.out.println("sb2 == sb3");


sb2의 StringBuffer class에서는 this를 반환

sb3에 넣어주고 두개를 비교하면

같다고 나오게 된다


이를 Method Chaining이라고 한다


ex)

String str2 = new StringBuffer().append("Hello").append(" World").toString();


import java.util.Random;


public class StringBufferExam{

  public String randomName(){

    StringBuffer sb = new StringBuffer();

    String[] firstNames = {"Tod", "John", "Michael"};

    String[] lastNames = {"Smith", "Brown", "Davis"};


    //0~3 사이의 임의의 숫자를 골라서

    int random1 = new Random().nextInt(3);

    //랜덤하게 이름을 뽑는다.

    String firstName = firstNames[random1];


    

    //0~3 사이의 임의의 숫자를 골라서

    int random2 = new Random().nextInt(3);

    //랜덤하게 성을 뽑는다.

    String lastName = lastNames[random2];


    //sb에 이름(fistName) 공백(" ") 성(lastname) 순으로 append해 보세요.

    //단 메소드 체이닝을 이용해야 합니다.

    return sb.append(firstName+" "+lastName).toString();

  }

  public static void main(String[]args){}

}


String class의 문제점


String str5 = "";

for(int j=0;j<100;j++) str5+="*";


이면 반복문 안에서 내부적으로 String 객체를 만듬

Java는 new가 많이 사용될수록 프로그램이 느려짐


이를 막으려면


StringBuffer sb = new StringBuffer();

for(int i=0;i<100;i++)

sb.append("*");


String sb6 = sb.toString();


훨씬 효율적인 코드를 만들어냄


public class StringBufferPerformanceTest{

        public static void main(String[] args){

                // (1) String의 +연산을 이용해서 10,000개의 *를 이어붙입니다.

                //시작시간을 기록합니다.(millisecond단위)

                long startTime1 = System.currentTimeMillis();

                String str="";

                for(int i=0;i<10000;i++){

                        str=str+"*";

                }

                //종료시간을 기록합니다.(millisecond단위)

                long endTime1 = System.currentTimeMillis();


                // (2) StringBuffer를 이용해서 10,000개의 *를 이어붙입니다.

                //시작시간을 기록합니다.(millisecond단위)                

                long startTime2 = System.currentTimeMillis();

                StringBuffer sb = new StringBuffer();

                for(int i=0;i<10000;i++){

                        sb.append("*");

                }

                //종료시간을 기록합니다.(millisecond단위)

                long endTime2 = System.currentTimeMillis();


                // 방법(1)과 방법(2)가 걸린 시간을 비교합니다.

                long duration1 = endTime1-startTime1;

                long duration2 = endTime2-startTime2;

                

                System.out.println("String의 +연산을 이용한 경우 : "+ duration1);

                System.out.println("StringBuffer의 append()을 이용한 경우 : "+ duration2);

        }

}


Math Class


int value1 = Math.max(5,30);

Math.min(5,10);

Math.abs(-10); //절댓값

Math.random(); //return은 double type

         //0~1.0미만

Math.sqrt(25); //제곱근

       //return은 double type


java.util


Deprecated : 더이상 지원하지 않으니 사용을 자제하라는 의미


자료구조 class : Collection Framework


Collection Framework


Generic


1) 기존 방식

모든 Object가 들어가기 때문에 나와서 사용할때 매번 형변환

 public class Box {

        private Object obj;

        public void setObj(Object obj){

        this.obj = obj;

        }


        public Object getObj(){

        return obj;

        }

    }


    public class BoxExam {

        public static void main(String[] args) {

            Box box = new Box();

            box.setObj(new Object());

            Object obj = box.getObj();


            box.setObj("hello");

            String str = (String)box.getObj();

            System.out.println(str);


            box.setObj(1);

            int value = (int)box.getObj();

            System.out.println(value);

        }

    }


2) Generic 사용하기

<E> : 가상 class


    public class Box<E> {

        private E obj;

        public void setObj(E obj){

            this.obj = obj;

        }


        public E getObj(){

            return obj;

        }

    }


    public class BoxExam {

        public static void main(String[] args) {

            Box<Object> box = new Box<>();

            box.setObj(new Object());

            Object obj = box.getObj();


            Box<String> box2 = new Box<>();

            box2.setObj("hello");

            String str = box2.getObj();

            System.out.println(str);


            Box<Integer> box3 = new Box<>();

            box3.setObj(1);

            int value = (int)box3.getObj();

            System.out.println(value);

        }

    }


Set

: Set은 interface!! new로 객체생성 불가

  HashSet은 Set을 구현한 Class

  Set은 중복을 허용하지 않음!


    import java.util.HashSet;

    import java.util.Iterator;

    import java.util.Set;


    public class SetExam {

        public static void main(String[] args) {

            Set<String> set1 = new HashSet<>();


            boolean flag1 = set1.add("kim");

            boolean flag2 = set1.add("lee");

            boolean flag3 = set1.add("kim");


            System.out.println(set1.size());   //저장된 크기를 출력합니다. 3개를 저장하였지만, 이미 같은 값이 있었기 때문에 2개가 출력

            System.out.println(flag1);  //true

            System.out.println(flag2);  //true

            System.out.println(flag3);  //false


            Iterator<String> iter = set1.iterator();


            while (iter.hasNext()) {   // 꺼낼 것이 있다면 true 리턴.          

                String str = iter.next(); // next()메소드는 하나를 꺼낸다. 하나를 꺼내면 자동으로 다음것을 참조한다.

                System.out.println(str);

            }

        }

    }


실습

import java.util.*;


public class SetExam{

  public static void main(String[] args){

    Set<String> set = new HashSet<String>();

    set.add("a");

    set.add("a");

    set.add("b");


    System.out.println("set의 내용을 출력합니다.");

    for(String str : set){

      System.out.println(str);

    }

  }

}


Array


List와 Array 비교



import java.util.ArrayList;

    import java.util.List;


    public class ListExam {


        public static void main(String[] args) {

            List<String> list = new ArrayList<>();


            // list에 3개의 문자열을 저장합니다.

            list.add("kim");

            list.add("lee");

            list.add("kim");


            System.out.println(list.size()); //list에 저장된 자료의 수를 출력 (중복을 허용하므로 3 출력) 

            for(int i = 0; i < list.size(); i++){

                String str = list.get(i);

                System.out.println(str);

            }

        }   

    }


Map

: key와 value를 쌍으로 Data를 저장하는 자료구조

  key를 이용해서 value를 찾으므로 key가 중복될 수는 없음

  만약에 같은 key가 들어오면 그 값으로 변경

  Map에 가지고 있는 Data를 모두 꺼내고 싶으면 key Set을 사용

  +) key set : key만 꺼내서 set이라는 자료구조에 넣음


    import java.util.HashMap;

    import java.util.Iterator;

    import java.util.Map;

    import java.util.Set;   

    public class MapExam {  

        public static void main(String[] args) {

            // Key, Value가 모두 String 타입인 HashMap인스턴스를 만듭니다.

            Map<String, String> map = new HashMap<>();


            // key와 value값을 put으로 저장합니다.

            map.put("001", "kim");

            map.put("002", "lee");

            map.put("003", "choi");

            // 같은 key가 2개 있을 수 없습니다. 첫번째로 저장했던 001, kim은 001, kang으로 바뀐다.

            map.put("001", "kang");


            // map에 저장된 자료의 수를 추력합니다. 3이 출력됩니다.

            System.out.println(map.size());


            // 키가 001, 002, 003인 값을 꺼내 출력합니다.

            System.out.println(map.get("001"));

            System.out.println(map.get("002"));

            System.out.println(map.get("003"));


            // map에 저장된 모든 key들을 Set자료구조로 꺼냅니다.

            Set<String> keys = map.keySet();


            // Set자료구조에 있는 모든 key를 꺼내기 위하여 Iterator를 구합니다.

            Iterator<String> iter = keys.iterator();

            while (iter.hasNext()) {


                // key를 꺼냅니다.

                String key = iter.next();


                // key에 해당하는 value를 꺼냅니다.

                String value = map.get(key);


                // key와 value를 출력합니다.

                System.out.println(key + " : " + value);

            }

        }

    }


Date


 Date date = new Date();

 System.out.println(date.toString());


 SimpleDateFormat ft =  new SimpleDateFormat ("yyyy.MM.dd 'at' hh:mm:ss a zzz");     

 System.out.println(ft.format(date));  


 System.out.println(date.getTime()); // System이 가지고 있는 currentTimeMillis()메소드를 이용해도 됩니다.

 long today = System.currentTimeMillis();

 System.out.println(today);


Calendar


현재는 Gregorian Calendar를 사용하고 있지만 

새로운 형식의 표준 달력이 나오면 그 달력을 쉽게 적용하기 위해 Calendar를 추상 클래스로 생성


Calendar클래스는 추상클래스이다.

Calendar클래스에 대한 인스턴스를 생성하려면 Calendar가 가지고 있는 클래스 메소드 getInstnace()를 사용해야 한다.

getInstance()메소드를 호출하면 내부적으로 java.util.GregorianCalendar 인스턴스를 만들어서리턴한다.

GregorianCalendar는 Calendar의 자식 클래스이다.


Calendar cal = Calendar.getInstance();


int yyyy = cal.get(Calendar.YEAR);

int month = cal.get(Calendar.MONTH) + 1; // 월은 0부터 시작합니다.

int date = cal.get(Calendar.DATE);

int hour = cal.get(Calendar.HOUR_OF_DAY);

int minute = cal.get(Calendar.MINUTE);


cal.add(Calendar.HOUR, 5);


import java.util.*;

import java.text.*; //SimpleDateFormat을 사용하기 위한 import


public class CalendarExam{

  public String hundredDaysAfter(){

    //오늘부터 100일 뒤의 날짜를 "2016년1월1일"의 형식으로 return하세요.

    SimpleDateFormat df = new SimpleDateFormat("yyyy년M월dd일");

    Calendar cal = Calendar.getInstance();

    cal.add(cal.DATE,100);

    return df.format(cal.getTime());

  }

  public static void main(String[] args){}

}


Time


LocalDateTime timePoint = LocalDateTime.now(); // 현재의 날짜와 시간

// 2012년 12월 12일의 시간에 대한 정보를 가지는 LocalDate객체를 만드는 방법  

LocalDate ld1 = LocalDate.of(2012, Month.DECEMBER, 12); // 2012-12-12 from values


// 17시 18분에 대한 LocalTime객체를 구한다.

LocalTime lt1 = LocalTime.of(17, 18); // 17:18 (17시 18분)the train I took home today


// 10시 15분 30초라는 문자열에 대한 LocalTime객체를 구한다.

LocalTime lt2 = LocalTime.parse("10:15:30"); // From a String


LocalDate theDate = timePoint.toLocalDate();

Month month = timePoint.getMonth();

int day = timePoint.getDayOfMonth();

int hour = timePoint.getHour();

int minute = timePoint.getMinute();

int second = timePoint.getSecond();

// 달을 숫자로 출력한다 1월도 1부터 시작하는 것을 알 수 있습니다. 

System.out.println(month.getValue() + "/" + day + "  " + hour + ":" + minute + ":" + second);


Java IO (Input / Output)


Decorator Pattern

: 하나의 클래스를 장식하는 것처럼 생성자에서 감싸서 새로운 기능을

계속 추가할 수 있도록 클래스를 만드는 방식



    public class ByteIOExam1 {

        public static void main(String[] args){     

            FileInputStream fis = null; 

            FileOutputStream fos = null;        

            try {

                fis = new FileInputStream("src/javaIO/exam/ByteExam1.java");

                fos = new FileOutputStream("byte.txt");


                int readData = -1; 

                while((readData = fis.read())!= -1){

                    fos.write(readData);

                }           

            } catch (Exception e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }finally{

                try {

                    fos.close();

                } catch (IOException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                }

                try {

                    fis.close();

                } catch (IOException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                }

            }

        }

    }


Byte 단위의 입출력


파일에서 511byte씩 읽음 하지만 위의 코드는 1byte만 얻어옴 -> 비효율적

따라서 512byte를 저장하는 buffer를 생성한 후 사용



    public class ByteIOExam1 {

        public static void main(String[] args){     

            //메소드가 시작된 시간을 구하기 위함

            long startTime = System.currentTimeMillis();        

            FileInputStream fis = null; 

            FileOutputStream fos = null;        

            try {

                fis = new FileInputStream("src/javaIO/exam/ByteExam1.java");

                fos = new FileOutputStream("byte.txt");


                int readCount = -1; 

                byte[] buffer = new byte[512];

                while((readCount = fis.read(buffer))!= -1){

                    fos.write(buffer,0,readCount);

                }

            } catch (Exception e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }finally{

                try {

                    fos.close();

                } catch (IOException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                }

                try {

                    fis.close();

                } catch (IOException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                }

            }

        //메소드가 끝났을때 시간을 구하기 위함. 

        long endTime = System.currentTimeMillis();

        //메소드를 수행하는데 걸린 시간을 구할 수 있음. 

        System.out.println(endTime-startTime); 

        }

    }


다양한 타입의 출력


    import java.io.DataOutputStream;

    import java.io.FileOutputStream;    

    public class ByteExam3 {    

        public static void main(String[] args) {

            try(

                    DataOutputStream out = new DataOutputStream(new FileOutputStream("data.txt"));

            ){

                out.writeInt(100);

                out.writeBoolean(true);

                out.writeDouble(50.5);

            }catch (Exception e) {

                e.printStackTrace();

            }

        }   

    }


다양한 타입의 입력


    import java.io.DataInputStream;

    import java.io.FileInputStream;


    public class ByteIOExam4 {


        public static void main(String[] args) {

            try(

                    DataInputStream out = new DataInputStream(new FileInputStream("data.dat"));

            ){

                int i = out.readInt();          

                boolean b = out.readBoolean();          

                double d = out.readDouble();


                System.out.println(i);

                System.out.println(b);

                System.out.println(d);

            }catch(Exception ex){

                ex.printStackTrace();

            }

        }

    }


char 단위 입출력 (Console)


Decorator Pattern

객체에 추가적인 요건(기능)을 동적으로 첨가하는 방식

서브클래스를 만드는 것을 통해 기능을 유연하게 확장할 수 있는 방법 제공


    import java.io.BufferedReader;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.PrintWriter; 

    public class CharIOExam01 {

        public static void main(String[] args) {

            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

            //키보드로 입력받은 문자열을 저장하기 위해 line변수를 선언               

            String line = null;     

            try {

                line = br.readLine()

            } catch (IOException e) {

                e.printStackTrace();

            }

            //콘솔에 출력 

            System.out.println(line);

        }

    }


char 단위 입출력 (File)


  import java.io.BufferedReader;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.PrintWriter; 

    public class CharIOExam02 {

        public static void main(String[] args) {

            BufferedReader br = null; 

            PrintWriter pw = null;

            try{        

                br = new BufferedReader(new FileReader("src/javaIO/exam/CharIOExam02.java"));

                pw = new PrintWriter(new FileWriter("test.txt"));

                String line = null;

                while((line = br.readLine())!= null){

                    pw.println(line);

                }

            }catch(Exception e){

                e.printStackTrace();

            }finally {

                pw.close();

                try {

                    br.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }

    }


어노테이션


클래스나 메소드 위에 붙여 사용 ex)@Override

소스코드에 메타코드(추가정보)를 주는 것

사용자 정의 가능 -> 커스텀 어노테이션 (정의->사용->실행)


Count100어노테이션을 JVM실행시에 감지할 수 있도록 하려면 @Retention(RetentionPolicy.RUNTIME)를 붙여줘야 합니다.

 

    import java.lang.annotation.Retention;

    import java.lang.annotation.RetentionPolicy;


    @Retention(RetentionPolicy.RUNTIME)

    public @interface Count100 {


    }


-------


   public class MyHello {

        @Count100

        public void hello(){

            System.out.println("hello");

        }

    }


-------


 import java.lang.reflect.Method;


    public class MyHelloExam {

        public static void main(String[] args) {

            MyHello hello = new MyHello();


            try{

                Method method = hello.getClass().getDeclaredMethod("hello");

            if(method.isAnnotationPresent(Count100.class)){

                    for(int i = 0; i < 100; i++){

                        hello.hello();

                    }

                }else{

                    hello.hello();

                }

            }catch(Exception ex){

                ex.printStackTrace();

            }       

        }

    }


Thread


운영체제에는 여러개의 process가 돌아가는데 jvm또한 그 안의 process중 하나이다

jvm에서도 운영체제처럼 여러개의 process가 돌아가게 구현하기 위해 Thread를 사용한다


-> 자바에서 Thread를 만드는 방법은 크게 Thread 클래스를 상속받는 방법과 Runnable인터페이스를 구현하는 방법이 있다.


OS : 컴퓨터의 하드웨어를 사용하게 해주는 프로그램


Process

: 현재 실행되고 있는 프로그램


java -> jvm에 의해 돌아감

우리가 만든 java program이 여러개의 작업을 할 수 있도록 만듬


  public class MyThread1 extends Thread {

        String str;

        public MyThread1(String str){

            this.str = str;

        }


        public void run(){

            for(int i = 0; i < 10; i ++){

                System.out.print(str);

                try {

                    //컴퓨터가 너무 빠르기 때문에 수행결과를 잘 확인 할 수 없어서 Thread.sleep() 메서드를 이용해서 조금씩 

                    //쉬었다가 출력할 수 있게한다. 

                    Thread.sleep((int)(Math.random() * 1000));

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            } 

        } 

    }


public class ThreadExam1 {

        public static void main(String[] args) {

            // MyThread인스턴스를 2개 만듭니다. 

            MyThread1 t1 = new MyThread1("*");

            MyThread1 t2 = new MyThread1("-");


            t1.start();

            t2.start();

            System.out.print("!!!!!");  

        }   

    }


//main이 종료가 됬음에도 불구하고 다른 thread들이 아직 돌아감

//thread 종료라고 선언하지 않으면 thread는 계속 돌고 있음


Thread 만들기 (Runnable Interface)


 public class MyThread2 implements Runnable {

        String str;

        public MyThread2(String str){

            this.str = str;

        }


        public void run(){

            for(int i = 0; i < 10; i ++){

                System.out.print(str);

                try {

                    Thread.sleep((int)(Math.random() * 1000));

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            } 

        } 

    }


    public class ThreadExam2 {  

        public static void main(String[] args) {

            MyThread2 r1 = new MyThread2("*");

            MyThread2 r2 = new MyThread2("-");


            Thread t1 = new Thread(r1);

            Thread t2 = new Thread(r2);


            t1.start();

            t2.start();

            System.out.print("!!!!!");  

        }   

    }


Thread와 공유객체


여러개의 Thread가 사용하고 있는 객체가 공유객체이다.


public class MusicBox { 

        //신나는 음악!!! 이란 메시지가 1초이하로 쉬면서 10번 반복출력

        public void playMusicA(){

            for(int i = 0; i < 10; i ++){

                System.out.println("신나는 음악!!!");

                try {

                    Thread.sleep((int)(Math.random() * 1000));

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            } // for        

        } //playMusicA


        //슬픈 음악!!!이란 메시지가 1초이하로 쉬면서 10번 반복출력

        public void playMusicB(){

            for(int i = 0; i < 10; i ++){

                System.out.println("슬픈 음악!!!");

                try {

                    Thread.sleep((int)(Math.random() * 1000));

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            } // for        

        } //playMusicB

        //카페 음악!!! 이란 메시지가 1초이하로 쉬면서 10번 반복출력

        public void playMusicC(){

            for(int i = 0; i < 10; i ++){

                System.out.println("카페 음악!!!");

                try {

                    Thread.sleep((int)(Math.random() * 1000));

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            } // for        

        } //playMusicC  

    }


public class MusicPlayer extends Thread{

        int type;

        MusicBox musicBox;  

        // 생성자로 부터 musicBox와 정수를 하나 받아들여서 필드를 초기화

        public MusicPlayer(int type, MusicBox musicBox){

            this.type = type;

            this.musicBox = musicBox;

        }       

        // type이 무엇이냐에 따라서 musicBox가 가지고 있는 메소드가 다르게 호출

        public void run(){

            switch(type){

                case 1 : musicBox.playMusicA(); break;

                case 2 : musicBox.playMusicB(); break;

                case 3 : musicBox.playMusicC(); break;

            }

        }       

    }


 public class MusicBoxExam1 {


        public static void main(String[] args) {

            // MusicBox 인스턴스

            MusicBox box = new MusicBox();


            MusicPlayer kim = new MusicPlayer(1, box);

            MusicPlayer lee = new MusicPlayer(2, box);

            MusicPlayer kang = new MusicPlayer(3, box);


            // MusicPlayer쓰레드를 실행합니다. 

            kim.start();

            lee.start();

            kang.start();           

        }   

    }


동기화 메소드와 동기화 블록

:

- 메소드 앞에 synchronized 를 붙힌다.

- 여러개의 Thread들이 공유객체의 메소드를 사용할 때 메소드에 synchronized가 붙어 있을 경우 먼저 호출한 메소드가 객체의 사용권       (Monitoring Lock)을 얻는다.

- 메소드 앞에 synchronized 를 붙혀서 실행해 보면, 메소드 하나가 모두 실행된 후에 다음 메소드가 실행된다.

- 해당 모니터링 락은 메소드 실행이 종료되거나, wait()와 같은 메소드를 만나기 전까지 유지된다.

- 다른 쓰레드들은 모니터링 락을 놓을때까지 대기한다.

- synchronized를 붙히지 않은 메소드는 다른 쓰레드들이 synchronized메소드를 실행하면서 모니터링 락을 획득했다 하더라도, 그것과 상관없이 실행된다.


public synchronized void playMusicA(){

        for(int i = 0; i < 10; i ++){

            System.out.println("신나는 음악!!!");

            try {

                Thread.sleep((int)(Math.random() * 1000));

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        } // for        

    } //playMusicA


synchronized를 메소드에 붙혀서 사용 할 경우, 메소드의 코드가 길어지면, 마지막에 대기하는 쓰레드가 너무 오래 기다리는것을 막기위해서 메소드에 synchronized를 붙이지 않고, 

문제가 있을것 같은 부분만 synchronized블록을 사용한다.


public void playMusicA(){

        for(int i = 0; i < 10; i ++){


   //synchronized block

   //이전에 monitoring lock을 가지고 있던 객체가 monitoring lock을 놓으면 실행

   //딱 한 줄만 lock이 있으니 다른 thread들이 더 빠르게 진입 가능

     //동기화를 method 전체가 아닌 부분만 가능


     synchronized (this){

            System.out.println("신나는 음악!!!");

    }

            try {

                Thread.sleep((int)(Math.random() * 1000));

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        } // for        

    } //playMusicA


Thread와 상태제어


Thread는 시간을 잘게 쪼개어 실행 (jvm) 그런데 시간 빠르기 때문에 한번에 실행하는 것처럼 보임



start() -> Runnable과 Running 상태

Thread.sleep() Thread.wait() 상태 -> Blocked

sleep : 특정 시간이 지나면 block 상태에서 빠져나옴

wait : notify나 notify all method가 실행되지 않으면 빠져 나올 수 없음

       또한 실행시 monitoring lock을 놓게됨 -> 다른 method가 실행

Dead : Thread의 run method 종료


Join Method

: Thread가 멈출때까지 기다리게 한다


    public class MyThread5 extends Thread{

        public void run(){

            for(int i = 0; i < 5; i++){

                System.out.println("MyThread5 : "+ i);

                try {

                    Thread.sleep(500);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        } // run

    }


   public class JoinExam { 

        public static void main(String[] args) {

            MyThread5 thread = new MyThread5();

            // Thread 시작 

            thread.start(); 

            System.out.println("시작");

            try {

                // 해당 쓰레드가 멈출때까지 멈춤

// main도 하나의 thread

//thread가 멈출때까지 main thread가 기다림

                thread.join();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println("종료"); 

        }   

    }


 시작

 MyThread5 : 0

 MyThread5 : 1

 MyThread5 : 2

 MyThread5 : 3

 MyThread5 : 4

 종료


Thread와 상태제어 wait, notify


  public class ThreadB extends Thread{

       // 해당 쓰레드가 실행되면 자기 자신의 모니터링 락을 획득

       // 5번 반복하면서 0.5초씩 쉬면서 total에 값을 누적

       // 그후에 notify()메소드를 호출하여 wiat하고 있는 쓰레드를 깨움 

        int total;

        @Override

        public void run(){

            synchronized(this){

                for(int i=0; i<5 ; i++){

                    System.out.println(i + "를 더합니다.");

                    total += i;

                    try {

                        Thread.sleep(500);

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

                notify();

            }

        }

    }


    public class ThreadA {

        public static void main(String[] args){

            // 앞에서 만든 쓰레드 B를 만든 후 start 

            // 해당 쓰레드가 실행되면, 해당 쓰레드는 run메소드 안에서 자신의 모니터링 락을 획득

            ThreadB b = new ThreadB();

            b.start();


            // b에 대하여 동기화 블럭을 설정

            // 만약 main쓰레드가 아래의 블록을 위의 Thread보다 먼저 실행되었다면 wait를 하게 되면서 모니터링 락을 놓고 대기       

            synchronized(b){

                try{

                    // b.wait()메소드를 호출.

                    // 메인쓰레드는 정지

                    // ThreadB가 5번 값을 더한 후 notify를 호출하게 되면 wait에서 깨어남

                    System.out.println("b가 완료될때까지 기다립니다.");

                    b.wait();

                }catch(InterruptedException e){

                    e.printStackTrace();

                }


                //깨어난 후 결과를 출력

                System.out.println("Total is: " + b.total);

            }

        }

    }


        b가 완료될때까지 기다립니다.

        0를 더합니다.

        1를 더합니다.

        2를 더합니다.

        3를 더합니다.

        4를 더합니다.

        Total is: 10


Demon Thread

: 보통 리눅스나 유닉스 계열의 운영체제에서 background로 동작하는 프로그램

ex) 주기적으로 자동으로 저장 or Editor에서 일정한 시간마다 맞춤법 검사

일반 Thread가 모두 종료되면 강제 종료


    // Runnable을 구현하는 DaemonThread클래스를 작성

    public class DaemonThread implements Runnable {


        // 무한루프안에서 0.5초씩 쉬면서 데몬쓰레드가 실행중입니다를 출력하도록 run()메소드를 작성

        @Override

        public void run() {

            while (true) {

                System.out.println("데몬 쓰레드가 실행중입니다.");


                try {

                    Thread.sleep(500);


                } catch (InterruptedException e) {

                    e.printStackTrace();

                    break; //Exception발생시 while 문 빠찌도록 

                }

            }

        }


        public static void main(String[] args) {

            // Runnable을 구현하는 DaemonThread를 실행하기 위하여 Thread 생성

            Thread th = new Thread(new DaemonThread());

            // 데몬쓰레드로 설정

            th.setDaemon(true);

            // 쓰레드를 실행

            th.start();


            // 메인 쓰레드가 1초뒤에 종료되도록 설정. 

            // 데몬쓰레드는 다른 쓰레드가 모두 종료되면 자동종료.

            try {

                Thread.sleep(1000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }   

    // main thread 1초간 유지 but Demon thread는 0.5초간 유지

    // 따라서 데몬 쓰레드가 실행중입니다 두번 출력

    // Demon Thread는 main Thread가 종료될때까지 종료되지 않음

            System.out.println("메인 쓰레드가 종료됩니다. ");    

        }   

    }


람다식 = 익명 메소드

인터페이스중에서 메소드를 하나만 가지고 있는 인터페이스를 함수형 인터페이스라고 한다

-> Runnable 인터페이스 경우 run method 하나만 가지고 있다.

-> method만 전달할 수 있다면 편리하게 프로그래밍을 할 수 있을 텐데 (객체 안만들고..) => 람다 표현식!


1) 이전

   public class LambdaExam1 {


        public static void main(String[] args) {

            new Thread(new Runnable(){

public void run(){

                for(int i = 0; i < 10; i++){

                    System.out.println("hello");

                }

            }}).start();

        }   

    }


2) 람다 표현식


    public class LambdaExam1 {  

        public static void main(String[] args) {

            new Thread(()->{

                for(int i = 0; i < 10; i++){

                    System.out.println("hello");

                }

            }).start();

        }   

    }


람다식 기본 문법

(매개변수 목록)->{실행해야 하는 문장}


    public interface Compare{

        public int compareTo(int value1, int value2);

    }


    public class CompareExam {


//Static을 사용한 이유는 main method가 static이기 때문이다.      

        public static void exec(Compare compare){

            int k = 10;

            int m = 20;

            int value = compare.compareTo(k, m);

            System.out.println(value);

        }

      

  public static void main(String[] args) {    

            exec((i, j)->{

                return i - j;

            }); }

    }


객체 List


import java.util.*;

public class CarExam{

  public static void main(String[] args){

    //Car객체를 만들어서 cars에 넣습니다.

    List<Car> cars = new ArrayList<>();

    cars.add( new Car("작은차",2,800,3) );

    cars.add( new Car("봉고차",12,1500,8) );

    cars.add( new Car("중간차",5,2200,0) );

    cars.add( new Car("비싼차",5,3500,1) );


    printCarCheaperThan(cars, 2000);

  }


  public static void printCarCheaperThan(List<Car> cars, int price){

    for(Car car : cars){

      if(car.price < price){

        System.out.println(car);

      }

    }

  }

}


//익명class

import java.util.*;

public class CarExam{

  public static void main(String[] args){

    List<Car> cars = new ArrayList<>();

    cars.add( new Car("작은차",2,800,3) );

    cars.add( new Car("봉고차",12,1500,8) );

    cars.add( new Car("중간차",5,2200,0) );

    cars.add( new Car("비싼차",5,3500,1) );


    printCar(cars, 

      //인터페이스 CheckCar를 구현하는 익명클래스를 만듭니다.

      new CheckCar(){

      public boolean test(Car car){

        return car.capacity >= 4 && car.price < 2500;

      }

    });

  }


  public static void printCar(List<Car> cars, CheckCar tester){

  for(Car car : cars){

  if (tester.test(car)) {

  System.out.println(car);

  }

  }

  }


  interface CheckCar{

  boolean test(Car car);

  }  

}


//람다

import java.util.*;

public class CarExam{

  public static void main(String[] args){

    //Car객체를 만들어서 cars에 넣습니다.

    List<Car> cars = new ArrayList<>();

    cars.add( new Car("작은차",2,800,3) );

    cars.add( new Car("봉고차",12,1500,8) );

    cars.add( new Car("중간차",5,2200,0) );

    cars.add( new Car("비싼차",5,3500,1) );


    CarExam carExam = new CarExam();

    printCar(cars, 

      //인터페이스 CheckCar의 test메소드에 대응하는 람다를 만듭니다.

      (Car car) -> { return car.capacity >= 4 && car.price < 2500; }

    );

  }


  public void printCar(List<Car> cars, CheckCar tester){

  for(Car car : cars){

  if (tester.test(car)) {

  System.out.println(car);

  }

  }

  }


  interface CheckCar{

  boolean test(Car car);

  }  

}

'STUDYING > JAVA' 카테고리의 다른 글

[JAVA] Version 관련  (0) 2018.02.09
[JAVA] Set List Map Vector Properties 예제  (0) 2017.10.20
[JAVA] 기본 개념 다지기 - 1  (0) 2017.10.02
[JAVA] JAVA로 게임 만들기 (환경 설정)  (0) 2017.06.09
[JAVA] 상속  (0) 2017.06.02
Comments