ランダ式


青多食?


近年,並列処理とイベント向けのプログラミングに適しているため,関数式プログラミングが再開されている.したがって,オブジェクト向けプログラミングと関数式プログラミングを組み合わせることで,プログラム開発言語がより効率的なプログラミングになるように変化している.

ランダ式基本文法


関数スタイルのram式を記述する方法は以下の通りです.(타입 매개변수, ...) -> { 실행문; ... }:(タイプパラメータ、...)カッコ{}ブロックを実行するために必要な値を指定します.
:->記号は、パラメータを使用してカッコ{}を実行するように解釈できます.
예를 들어, int 매개변수 a의 값을 콘솔에 출력하기 위해 람다식을 작성한다면
(int a) -> { System.out.println(a); }

関数インタフェース(@Functional Interface)


:ラムダ式は1つの方法を定義しているため、2つ以上の抽象的な方法を宣言したインタフェースはラムダ式を使用して実装オブジェクトを作成できません.
従来のインタフェースの使い方は以下の通りです.
// 인터페이스를 선언한 뒤
interface A1 {
	void aMethod();
}

// (1)
//  일반 클래스에 implements A 로 연결해서 오버라이드 후
class AA implements A{
	@Override
	public void aMethod() {}; {};
}
// 메인에서 객체화해 사용
AA aa = new AA();


// (2)
// 아니면 메인에서 객체 생성하면서 익명 구현 객체로 생성해 사용
A1 ac = new A1() {	
	@Override
	public void aMethod() {
		int a = 5;
		a++;
	}
};
:インタフェース宣言時に@FunctionalInterfaceフレーズを追加すると、コンパイラは関数インタフェースの作成時に2つ以上の抽象メソッドをチェックし、宣言されないようにします.
@FunctionalInterface
interface A {
	void aMethod();
}

パラメータと戻り値のないラムダ式


  • public class A_LambdaEx {
    	public static void main(String[] args) {
    		A1 ac = () -> {
    			int a = 5;
    			a++;
    		};
    		
    		// 람다식으로 익명구현 객체 만들고
    		B1 bc = () -> {
    			// 메소드 재 정의한 부분
    			int b = 5;
    			b++;
    		};
    		// 메소드 호출해서 값 넣어주기
    		bc.bMethod();
    	}
    }
    interface A1 {
    	void aMethod();
    }
    interface B1 {
    	void bMethod();
    }
  • -----------------------------------------------------------
  • public class B_LambdaEx {
    	public static void main(String[] args) {
    		//인터페이스 구현방법
    		// 1. 클래스에 implements로 연결하고 재정의 후 메인에서 해당 클래스를 객체 생성해 사용
    		// 2. 익명 구현 객체로 메인에 생성
    		A2 a2 = new A2() {
    			@Override
    			public void a2Method() {
    				System.out.println("람다식 연습");
    			}
    		};
    		
    		// 3. 람다식으로 생성
    		A2 aa2 = () -> {System.out.println("람다식 연습");};
    		A2 aaa2 = () -> System.out.println("람다식 연식");
    		
    		aa2.a2Method();
    		aaa2.a2Method();
    		
    	}
    }
    
    // 인터페이스 하나에 추상메소드도 하나
    // = 함수적 인터페이스
    interface A2 {
    	void a2Method();
    }

    パラメータ付きRam多項式


    次のコードから分かるように、ラムダ式の基本形状は인터페이스 매개변수 = () -> {실행문}形態ですが、使用を減らすこともできます.例を挙げるとそうです.
    // 근데 이제 이런식으로 작성해도 된다
    // 들어가는 값이 하나이고 실행문도 하나라면 아래 식들은 모두 같은 식이다
    D1 d1 = (int a) -> { System.out.println(a); };
    D1 d2 = (a) -> { System.out.println(a); };
    D1 d3 = a -> System.out.println(a);

  • public class C_MyFunctionalInterfaceEx2 {
    	public static void main(String[] args) {
    		MyFunctionalInterface2 mi;
    
    		mi = (int x) -> {
    			int result = x * 5;
    			System.out.println(result);
    		};
    		mi.method(2);
    		
    		mi = (x) -> {System.out.println(x * 5);};
    		mi.method(2);
    		
    		mi = x -> {System.out.println(x * 5);};
    		mi.method(2);
    		
    		mi = x -> System.out.println(x * 5);
    		mi.method(2);
            
            	// 근데 이제 이런식으로 작성해도 된다
    		// 들어가는 값이 하나이고 실행문도 하나라면 아래 식들은 모두 같은 식이다
    		D1 d1 = (int a) -> { System.out.println(a); };
    		D1 d2 = (a) -> { System.out.println(a); };
    		D1 d3 = a -> System.out.println(a);
    	}
    }
    
    @FunctionalInterface
    interface MyFunctionalInterface2 {
    	void method(int x);
    }
    interface D1 {
    	void dMethod(int a);
    }

    戻り値のあるランダ式

    // 인터페이스를 이럴식으로 작성했다고 했을 때
    @FunctionalInterface
    interface C1 {
    	int cMethod(int a, int c);
    }
    
    // 사용은 아래와 같이 할 수 있다.
    
    // 만약 들어가는값이 여러개이고 실행문이 하나라면
    C1 c1 = (int x, int y) -> { return x+y; };
    C1 c2 = (x, y) -> { return x+y; };
    // 매개값이 두개일때는 괄호 제거시 에러
    // C1 c3 = x,y -> { return x+y; };
    // 실행문이 리턴이라면 괄호 제거할때 "return" 작성하지 않아도 괜찮다
    C1 c4 = (x, y) -> x+y;

    クラスメンバーとローカル変数の使用


    ラムダ式の実行ブロックは、クラスのメンバー(フィールドおよびメソッド)およびローカル変数を使用することができる.クラスのメンバーは使用可能ですが、ローカル変数は制約されています.

    クラス内のメンバーの使用


    ラムダ式では,thisは内部で生成された匿名オブジェクトへの参照ではなく,ラムダ式を実行するオブジェクトへの参照である.
    public class D_UsingThisEx {
    	public static void main(String[] args) {
    		UsingThis usingthis = new UsingThis();
    		UsingThis.Inner inner = usingthis.new Inner();
    		inner.method();
    	}
    }
    
    @FunctionalInterface
    interface MyFunctionalInterface4 {
    	void method();
    }
    
    class UsingThis {
    	int outterfield = 10;
    	int a = 5;
    	
    	class Inner {
    		int ineerField = 20;
    		int a = 10;
    		
    		void method() {
    			// 람다식
    			MyFunctionalInterface4 fi = () -> {
    				// 호출 방식의 차이이지 결국 같은 것릉 불러오는 것
    				System.out.println("outterField : " + outterfield);
    				System.out.println("outterField : " + UsingThis.this.outterfield + "\n");
    				
    				// 호출 방식의 차이이지 결국 같은 것을 불러오는 것
    				System.out.println("innerField : " + ineerField);
    				System.out.println("innerField : " + this.ineerField + "\n");
    				
    				// this를 사용한 호출 방식의 차이
    				System.out.println("UsingThis에서 불러오는 a값 : " + UsingThis.this.a);
    				System.out.println("가장 가까이 있는 a 값 : " + this.a);
    			};
    			fi.method();
    		}
    	}
    }
    運転状態

    ローカル変数の使用


    ラムダ式では、外部クラスのフィールドまたはメソッドは制限されませんが、メソッドのパラメータまたはローカル変数を使用する場合、この2つの変数はfinal特性を持つ必要があります.
    class UsingLocalVariable {
    	void method(int arg) {  //arg는 final 특성을 가짐
    		int localVar = 40; 	//localVar는 final 특성을 가짐
    		
    //		arg = 31;  		//final 특성 때문에 수정 불가
    //		localVar = 41; 	//final 특성 때문에 수정 불가
            
    		//람다식
    		// = 익명 구현 객체로 작성할 것을 간단히 작성
    		MyFunctionalInterface5 fi= () -> {
    			//로컬변수 사용
    			// 내부에서 원래 값을 호출할 수 있지만
    			// 변경된 값을 가져오는 것은 xx
    			
    			// 내부에서 값을 변경하는 것도 xx
    			// arg = 30;
    			System.out.println("arg: " + arg); 
    			System.out.println("localVar: " + localVar + "\n");
    		};
    		fi.method();
    	}
    }

    標準APIの関数インタフェース


    Java 8から、頻繁に使用される関数インタフェース(functional interface)はjavaである.util.関数標準APIパッケージとして提供されます.このパッケージで提供される関数インタフェースの目的は、ramda式を代入するために、メソッドまたは構造関数のパラメータタイプとして使用されます.
    関数インタフェースは,Consumer,Supplier,Function,Operator,Predicateに大別される.分離条件には、インタフェースで宣言された抽象メソッドのパラメータ値と戻り値は含まれません.

    Consumer関数インタフェース


    戻り値のないaccept()メソッドが特徴です.accept()メソッドは、各値を消費する役割のみを果たします.
    Consumer<T>インタフェースをターゲットとするramda式は、以下のように書くことができる.Consumer<타입> consumer = t -> { t를 소비하는 실행문; };

    活用コード01

    public class A_ConsumerEx {
    	public static void main(String[] args) {
    		// 람다식으로 익명구현 객체 클래스를 재정의함
    		// consumer인터페이스를 String타입으로 사용하겠다
    		// (String s)에서 String 생략 가능
    		// 실행문이 하나이기 때문에 중괄호 {}도 생략
    		Consumer<String> consumer1 = s -> System.out.println(s + " 8");
    		// 사용하기
    		consumer1.accept("Java");
    		
    		
    		Consumer<Integer> consumer2 = t -> System.out.println(t + 10);
    		consumer2.accept(10);
    		
    		
    		Consumer<Integer> consumer3 = t -> { t++; System.out.println(t); };
    		consumer3.accept(10);
    		
    		Consumer<Double> consumer4 = t -> { t = t-2.2; System.out.println(t); };
    		consumer4.accept(3.2);
    		
    		
    		// true를 넣어 판단하기
    		Consumer<Boolean> consumer5 = b -> {
    			if (b) {
    				System.out.println("참 입니다");
    			} else {
    				System.out.println("거짓입니다");
    			}
    		};
    		consumer5.accept(true);
    		consumer5.accept(false);
    	}
    }

    活用コード02

    public class A_ConsumerEx2 {
    	public static void main(String[] args) {
    		BiConsumer<String, String> biConsumer1 = (s1, u1) ->{
    			System.out.println(s1 + u1);
    		};
    		biConsumer1.accept("java", " Lambda");
    		
    		BiConsumer<Integer, Double> biConsumer2 = (s1, u1) -> {
    		System.out.println(s1 + "*" + u1 + "=" +s1*u1);
    		};
    		biConsumer2.accept(10, 80.9);
    
    		
    		System.out.println();
    		// Double 컨슈머 사용해보기
    		DoubleConsumer dc = v -> System.out.println(v);
    		dc.accept(10.9);
    		
    		
    		System.out.println();
    		// "홍길동" 85.3을 넣어 소비하고 싶다면
    		ObjDoubleConsumer<String> objDouble= (s, d) -> {
    			System.out.println(s + d);
    		};
    		objDouble.accept("홍길동", 85.3);
    		
    		//520L long숫자 넣어 소비하기
    		LongConsumer lc = l -> System.out.println(l);
    		lc.accept(520L);
    		
    		// 정수 100 넣어서 소비하기
    		IntConsumer ic = i -> System.out.println(i);
    		ic.accept(100);
    	}
    }

    Supplier関数インタフェース


    Supplier関数インタフェースの特徴は,パラメータがなく戻り値を持つgetXXX()メソッドである.これらのメソッドは、実行後に呼び出された場所にデータを返す役割を果たします.
    戻りタイプに応じて、次の関数インタフェースがあります.

    ランダ式は次のように書くことができます.Supplier<T> supplier = () -> {...; return T값; }get()メソッドは各値を持たないのでramda式()を使用します.青かっこ{}はTオブジェクトを返さなければなりません.

    試用01

    ublic class A_SupplierEx {
    	public static void main(String[] args) {
    		// 입력은 없고, 정수값만 출력하기
    		
    		// 람다식으로 메소드를 재정희한 것
    		// int getAsInt();
    		IntSupplier iS = () -> {
    			int num = (int) (Math.random() * 6) + 1;
    			return num;
    		};
    		int number = iS.getAsInt();
    		System.out.println(number);
    		
    		
    		// 참/거짓을 출력하기
    		// boolean getAsBoolean
    		BooleanSupplier iS2 = () -> {
    			int num = (int) (Math.random() * 2);
    			if(num == 1) {
    				return true;
    			} else {
    				return false;
    			}
    		};
    		boolean result = iS2.getAsBoolean();
    		System.out.println(result);
    		
    		
    		Student st = new Student();
    		st.setName("홍길동");
    		st.setScore(90);
    		Supplier<Student> iS3 = () -> {
    			return st;
    		};
    		System.out.println(iS3.get().getName() + " " + iS3.get().getScore());
    		
    		// 컨슈머도 사용해보기
    		Consumer<Student> cS = (t) -> {
    			st.set("김자바", 100);
    			System.out.println(st.getName() + " " + st.getScore());
    		};
    		cS.accept(st);
    	}
    }
    
    class Student {
    	String name;
    	int score;
    	public Student() { }
    	void set(String name, int score) {
    		this.name = name;
    		this.score = score;
    	}
    	void setName(String name) {
    		this.name = name;
    	}
    	void setScore(int score) {
    		this.score = score;
    	}
    	int getScore() {
    		return score;
    	}
    	String getName() {
    		return name;
    	}
    }

    入力はConsumer、出力はSupplier

    public class A_SupplierConsumerTest {
    	public static void main(String[] args) {
    		Car car = new Car();
    		
    		// 입력 Consumer
    		Consumer<Car> co = (t) -> {
    			t.set("소나타", 1000, true);
    		};
    		co.accept(car);
    		// 출력 Supplier
    		Supplier<Car> sp = () -> {
    			return car;
    		};
    		System.out.println(sp.get().carName + " " + sp.get().price + " " + sp.get().newOld);
    	}
    }
    
    class Car {
    	String carName;
    	int price;
    	boolean newOld;
    	
    	void set(String carName, int price, boolean newOld) {
    		this.carName = carName;
    		this.price = price;
    		this.newOld = newOld;
    	}
    	String getCarName() {
    		return carName;
    	}
    	int getPrice() {
    		return price;
    	}
    	boolean getNewOld() {
    		return newOld;
    	}
    }

    ファンクション関数インタフェース


    各値と戻り値を持つapplyXXX()メソッドが特徴です.これらの方法は、パラメータ値をマッピング(変換タイプ)して値を返す役割を果たします.

    Functionインタフェースをターゲットとするram式は、次のように記述できます.
    // '객체' 가 들어가면 '해당 타입'으로 나온다
    // 객체에 있는 Name을 가져오겠다
    Function< 객체, 타입 > function = t -> { return t.getName(); }
    
    또는
    
    // 실행할 내용이 리턴문 하나라면
    // 중괄호 제거와 return 제거가 가능하다 
    Functin < 객체, 타입> function = t -> t.getName;

    Function関数インタフェース01の使用

    public class A_FuncionEx1 {
    	// 배열로 만들어서 리스트 만들기
    	private static List<Student> list = Arrays.asList(
    			new Student("홍길동", 90, 96, true),
    			new Student("신용권", 95, 93, false)
    			);
    	
    	// Student가 들어가면 String이 나온다라는 function
    	public static void printString( Function<Student, String> function ) {
    		// list에 저장된 항목 수 만큼 반복
    		for(Student student : list) {
    			// 람다식 실행
    			System.out.println(function.apply(student) + " ");
    		}
    		System.out.println();
    	}
    	
    	// ToIntFunction<Student> function
    	// printInt( t -> t.getMathScore());
    	// t가 function에 들어가 int로 매핑된다
    	public static void printInt( ToIntFunction<Student> function ) {
    		for(Student student : list) {
    			// ToIntFunction의 추상 메소드는 applyAsInt(T value)
    			System.out.println(function.applyAsInt(student) + " ");
    		}
    		System.out.println();
    	}
    	
    	// 성별 넣기
    	public static void printBoolean( Function<Student, Boolean> function) {
    		for(Student student : list) {
    			// 값을 가져와서 gender에 넣는데 만약 true라면 여성, false라면 남성이 출력되도록 지정
    			boolean gender = function.apply(student);
    			if (gender == true) {
    				System.out.println("여성");
    			} else {
    				System.out.println("남성");
    			}
    		}
    		System.out.println();
    	}
    	
    	public static void main(String[] args) {
    		System.out.println("[학생 이름]");
    		printString(t -> t.getName());
    		
    		System.out.println("[영어 점수]");
    		printInt( t -> t.getEngScore());
    		
    		System.out.println("[수학 점수]");
    		printInt( t -> t.getMathScore());
    		
    		System.out.println("[학생 성별]");
    		printBoolean(t -> t.isGender());
    	}
    }
    
    class Student {
    	private String name;
    	private int englishScore;
    	private int mathScore;
    	private boolean gender;
    	
    	public Student(String name, int englishScore, int mathScore, boolean gender) {
    		this.name = name;
    		this.englishScore = englishScore;
    		this.mathScore = mathScore;
    		this.gender = gender;
    	}
    	
    	public String getName() { return name; }
    	public int getEngScore() { return englishScore; }
    	public int getMathScore() { return mathScore; }
    	public boolean isGender() { return gender; }
    }

    試用02


    要求:2つの値を入力し、1つの値を出力します.
    この場合、方法は2つあります.
    1.Function<オブジェクト、タイプ>
    2.BiFunctions<オブジェクト、タイプ>
    似ているように見えますが、使い方が違うので快適に使いましょう.
    public class A_FunctionEx2 {
    	private static List<Student_> list = Arrays.asList(
    			// 1학년
    			new Student1("홍길동", 90, 96, true),
    			new Student1("신용권", 95, 93, false),
    			// 2학년
    			new Student2("이순신", 100, 95, true),
    			new Student2("김자바", 98, 90, false)
    			);
    	
    	private static List<Student_> list1 = Arrays.asList(
    			// 1학년
    			new Student1("홍길동", 90, 96, true),
    			new Student1("신용권", 95, 93, false)
    			);
    	private static List<Student_> list2 = Arrays.asList(
    			// 2학년
    			new Student2("이순신", 100, 95, true),
    			new Student2("김자바", 98, 90, false)
    			);
    	
    	
    	
    	// 값 두개 넣고 1개 출력하는 함수적 인터페이스를 찾기 
    	// 방법 1
    	public static void printString1( Function<Student_, String> function) {
    		for(Student_ st : list) {
    			System.out.println(function.apply(st) + " ");
    		}
    		System.out.println();
    	}
    	
    	// 방법 2
    	public static void printString2( BiFunction<Student1, Student2, String> function1 ) {
        		// 객체를 넣었기 때문에 size나 길이 혹은 향상된 for문으로 돌릴 시
                	// 에러남. 길이를 안다면 그 길이대로 돌리는 것이 안전하다
    		for(int i=0; i<2; i++) {
    			Student1 st1 = (Student1) list1.get(i);
    			Student2 st2 = (Student2) list2.get(i);
    			System.out.println(function1.apply(st1, st2));
    		}
    		System.out.println();
    	}
    	
    	
    	public static void main(String[] args) {
    		System.out.println("[학생 이름]");
    		printString1(t -> t.getName());
    		System.out.println();
    
    		System.out.println("[학생 이름]");
    		printString2((t, u)-> t.getName() + "\n" + u.getName());
    	}
    }
    
    // 상위 클래스
    class Student_{
    	String name;
    	public Student_() {
    	}
    	public String getName() {
    		return name;
    	}
    }
    
    // 1학년
    class Student1 extends Student_{
    	String name;
    	private int englishScore;
    	private int mathScore;
    	private boolean gender;
    	
    	public Student1(String name, int englishScore, int mathScore, boolean gender) {
    		this.name = name;
    		this.englishScore = englishScore;
    		this.mathScore = mathScore;
    		this.gender = gender;
    	}
    	public String getName() { return name; }
    	public int getEngScore() { return englishScore; }
    	public int getMathScore() { return mathScore; }
    	public boolean isGender() { return gender; }
    }
    
    // 2학년
    class Student2 extends Student_ {
    	String name;
    	private int englishScore;
    	private int mathScore;
    	private boolean gender;
    
    	public Student2(String name, int englishScore, int mathScore, boolean gender) {
    		this.name = name;
    		this.englishScore = englishScore;
    		this.mathScore = mathScore;
    		this.gender = gender;
    	}
    	public String getName() { return name; }
    	public int getEngScore() { return englishScore; }
    	public int getMathScore() { return mathScore; }
    	public boolean isGender() { return gender; }
    }