Skip to content

rxgp1/Java8-functional-tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

55 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Java 8 Functinal Programming Tutorial.


Java 8 은 Lambda ν‘œν˜„μ‹κ³Ό Stream API λ₯Ό μ΄μš©ν•˜μ—¬ Functinal ν”„λ‘œκ·Έλž˜λ°μ„ μ§€μ›ν•œλ‹€. 이 νŠœν† λ¦¬μ–Όμ—μ„œ 사전에 μ •μ˜λœ Functional interfaces와 Collctions API 그리고 Stream APIλ₯Ό 톡해 Java8 이 μ–΄λ–€μ‹μœΌλ‘œ Functioanl ν”„λ‘œκ·Έλž˜λ°μ„ μ§€μ›ν•˜λŠ”μ§€ μ•Œμ•„λ³Έλ‹€.


1. Java8 Functional Programming μ†Œκ°œ

Java λŠ” 객체 μ§€ν–₯ ν”„λ‘œκ·Έλž˜λ° 언어이닀.
Java8 은 Lambda ν‘œν˜„μ‹μ„ 톡해 Functional programming 을 μ§€μ›ν•œλ‹€.

λžŒλ‹€ ν‘œν˜„μ‹μ€ λ‹€μŒμ˜ λ¬Έλ²•μœΌλ‘œ νŠΉμ • μ§€μ–΄ μ§„λ‹€. (콀마둜 κ΅¬λΆ„λœ μ—¬λŸ¬κ°€μ§€μ˜ νŒŒλΌλ©”ν„°) -> {ν•˜λ‚˜ μ΄μƒμ˜ λ°”λ”” 처리}

JDK 의 μ»΄νŒŒμΌλŸ¬κ°€ type interface λ₯Ό μ§€μ›ν•˜κΈ°μ— λžŒλ‹€ ν‘œν˜„μ‹μ€ 두가지 λ°©λ²•μœΌλ‘œ 짧은 ν‘œν˜„μ΄ κ°€λŠ₯ν•˜λ‹€.

  • νŒŒλΌλ©”ν„°μ˜ νƒ€μž…μ„ μ œμ™Έ ν• μˆ˜ μžˆλ‹€. μ»΄νŒŒμΌλŸ¬λŠ” νŒŒλΌλ©”ν„°μ˜ κ°’μœΌλ‘œ νƒ€μž…μ„ μœ μΆ” ν• μˆ˜ μžˆλ‹€.
  • λžŒλ‹€ μ²˜λ¦¬μ‹œ λ°”λ””κ°€ 단일 ν‘œν˜„μ‹μ΄λ©΄ return ν‚€μ›Œλ“œλ₯Ό μ œμ™Έμ‹œν‚¬μˆ˜ μžˆλ‹€.

λ˜ν•œ λ‹€μŒμ˜ μƒν™©μ—μ„œ μ’€ 더 λ‹¨μˆœν‘œν˜„μ΄ κ°€λŠ₯ν•˜λ‹€.

  • 단일 νŒŒλΌλ©”ν„°μ—μ„œ κ΄„ν˜Έλ₯Ό μƒλž΅ ν• μˆ˜ μžˆλ‹€.
  • ν‘œν˜„μ‹μ˜ λ°”λ””κ°€ 단일 처리일 경우 μ€‘κ΄„ν˜ΈλŠ” μƒλž΅ ν• μˆ˜ μžˆλ‹€.

Functional programming 은 νŒŒλΌλ©”ν„°λ‚˜ Function 자체둜 λ°˜ν™˜ν•˜μ—¬ μ „λ‹¬ν•˜λŠ” κ³ κΈ°λŠ₯ Function을 μ§€μ›ν•œλ‹€. λ˜ν•œ μƒˆλ‘œμš΄ stream API λ˜ν•œ κ³ κΈ°λŠ₯ Function을 μ§€μ›ν•œλ‹€.

ν•΄λ‹Ή νŠœν† λ¦¬μ–Όμ—μ„œλŠ” Java8 μ—μ„œ Functional ν”„λ‘œκ·Έλž˜λ°μ„ 기본적으둜 사전에 μ •μ˜λœ μΈν„°νŽ˜μ΄μŠ€λ“€κ³Ό Collections, 그리고 Stream API 둜 μ„€λͺ…ν•œλ‹€.

2. μ‚¬μš©λ²•

ν˜„μž¬ κΈ€μ˜ μ˜ˆμ œλŠ” λ‹€μŒμ˜ λ²„μ „μœΌλ‘œ λΉŒλ“œλ˜κ³  μ‹€ν–‰λœλ‹€.

  • Java 1.8.101
  • Maven 3.3.9
  • Eclipse Oxygen
  • JUnit 4.12

2.1. Maven Project

μ΄λ²ˆμ—λŠ” Junit 라이브러리λ₯Ό ν¬ν•¨ν•œ Maven Project λ₯Ό μƒμ„±ν•œλ‹€.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"<br>
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br>
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><br>
    <modelVersion>4.0.0</modelVersion><br>
    <groupId>zheng.jcg.demo</groupId><br>
    <artifactId>java8-demo</artifactId><br>
    <version>0.0.1-SNAPSHOT</version><p></p>
<p> <dependencies><br>
        <dependency><br>
            <groupId>junit</groupId><br>
            <artifactId>junit</artifactId><br>
            <version>4.12</version><br>
            <scope>test</scope><br>
        </dependency><br>
    </dependencies><br>
    <build><br>
        <plugins><br>
            <plugin><br>
                <artifactId>maven-compiler-plugin</artifactId><br>
                <version>3.3</version><br>
                <configuration><br>
                    <source>1.8</source><br>
                    <target>1.8</target><br>
                </configuration><br>
            </plugin><br>
        </plugins><br>
    </build><br>
</project></p>

3. 사전 μ •μ˜λœ Functional Interfaces

Functional Interface (FI) λŠ” java.lang.object λ‘œλΆ€ν„° 상속받지 μ•ŠμœΌλ©° ν•˜λ‚˜μ˜ abstract λ©”μ†Œλ“œλ₯Ό κ°€μ§„ μΈν„°νŽ˜μ΄μŠ€ 이닀.

Functional Programming 의 ν•œκ°€μ§€ νŠΉμ§•μ€ 순수 Function 이닀. 순수 Function 은 μž…λ ₯κ³Ό 좜λ ₯을 μ²˜λ¦¬ν•œλ‹€. λ˜ν•œ ν•΄λ‹Ή μ²˜λ¦¬λŠ” μ–΄λ– ν•œ μƒν™©μ—μ„œλ„ λ³€ν•˜μ§€ μ•ŠλŠ” 것을 λͺ©μ μœΌλ‘œ ν•œλ‹€.
κ·ΈλŸ¬λ―€λ‘œ ν•΄λ‹Ή μ²˜λ¦¬λŠ” μ–΄λ– ν•œ μ‚¬μ΄λ“œ μ΄νŒ©νŠΈλ„ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€.
항상 λ™μΌν•œ 좜λ ₯κ³Ό μž…λ ₯을 μ²˜λ¦¬ν•œλ‹€.

Java 8 은 40κ°€μ§€ μ΄μƒμ˜ 사전에 μ •μ˜λœ Functional interfaces λ₯Ό μ œκ³΅ν•œλ‹€. Consumer λ₯Ό μ œμ™Έν•œ λͺ¨λ“  FI λŠ” 순수 Function듀이닀.

Java8 μ°Έμ‘° λ©”μ†Œλ“œλŠ” λžŒλ‹€μ‹μ˜ 단 ν•œκ°€μ§€ 싀행을 μœ„ν•΄ 짧게 ν‘œν˜„ν• μˆ˜ μžˆλ‹€. κ°œλ°œμžλŠ” λžŒλ‹€μ‹μ΄λ‚˜ μ°Έμ‘° λ©”μ†Œλ“œλ₯Ό FI 둜 μ‚¬μš©ν• μˆ˜ μžˆλ‹€. Java8 Stream API λŠ” 사전 μ •μ˜λœ FI듀을 Steam 을 μœ„ν•΄ μ‚¬μš©ν• μˆ˜ μžˆλ‹€.

이번 μž₯μ—μ„œλŠ” 곡톡 Functional Interface듀을 μ–΄λ–€μ‹μœΌλ‘œ μ‚¬μš©ν• μ§€ JUnit 클래슀λ₯Ό μƒμ„±ν•˜μ—¬ 보여쀀닀.

3.1. Function

Function FI λŠ” ν•˜λ‚˜μ˜ νŒŒλΌλ©”ν„° λ°›μ•„ 듀이며 ν•˜λ‚˜μ˜ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€. Function FI λŠ” abstract λ©”μ†Œλ“œμΈ apply(Object) λ₯Ό ν˜ΈμΆœν•œλ‹€.

Java8 은 μ›μ‹œ 데이터 νƒ€μž…μ„ μœ„ν•΄ 각각 μ‚¬μš©ν•˜κΈ° μš©μ΄ν•œ FI듀을 μ œκ³΅ν•œλ‹€: IntFunction, DoubleFunction, IntToDoubleFunction, IntToLongFunction, DoubleToIntFunction, DoubleToLongFunction, LongToDoubleFunction, 그리고 LongToIntFunction.

BitFunction FI λŠ” λ‘κ°€μ§€μ˜ νŒŒλΌλ©”ν„°λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ λ°›μœΌλ©° 처리된 κ²°κ³Όλ₯Ό λ¦¬ν„΄ν•œλ‹€. BitFunction FI λŠ” abrtract λ©”μ†Œλ“œμΈ apply(Object, Object) λ₯Ό ν˜ΈμΆœν•œλ‹€.

Java8 은 λ˜ν•œ 두가지 νŒŒλΌλ©”ν„°λ₯Ό 맀게 λ³€μˆ˜λ‘œ λ°›μœΌλ©° 처리된 κ²°κ³Όλ₯Ό Doubleκ°’, Intκ°’, Long 값을 λ°˜ν™˜ν•˜λŠ” ToDoubleBiFunction, ToIntBiFunction, ToLongBiFunction λ₯Ό μ œκ³΅ν•œλ‹€.

이번 μž₯μ—μ„œλŠ” FunctionTest.java 클래슀λ₯Ό λ‹€μŒμ„ μ„€λͺ…ν•˜κΈ° μœ„ν•΄ μƒμ„±ν•˜μ˜€λ‹€.

  • Integer 클래슀λ₯Ό String 클래슀둜 λ³€ν™˜
  • λ¬Έμžμ—΄μ˜ 길이λ₯Ό Integer ν˜•μœΌλ‘œ λ°˜ν™˜
  • 두가지 Function을 μƒˆλ‘œμš΄ Function으둜 κ²°ν•©
  • 리슀트의 속성듀을 Stream-map(Function <T, R>) λ₯Ό ν†΅ν•˜μ—¬ λ³€ν™˜ν•œλ‹€.
  • IntFunction, DoubleFunction, λ“±λ“±μ˜ μ‚¬μš©λ²•μ„ 보여쀀닀.

FunctionTest.java

 
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
 
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.DoubleFunction;
import java.util.function.DoubleToIntFunction;
import java.util.function.DoubleToLongFunction;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.IntToDoubleFunction;
import java.util.function.IntToLongFunction;
import java.util.function.LongToDoubleFunction;
import java.util.function.LongToIntFunction;
import java.util.function.ToDoubleBiFunction;
import java.util.function.ToIntBiFunction;
import java.util.function.ToLongBiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
import org.junit.Test;
 
import com.zheng.demo.DataUtil;
import com.zheng.demo.model.LoginUser;
 
public class FunctionTest {
 
    @Test
    public void BiFunction_concat_two_String() {
        BiFunction<String, String, String> concat = (a, b) -> a + b;
        String combinedStr = concat.apply("Today is", " a wonderful day");
        assertEquals("Today is a wonderful day", combinedStr);
    }
 
    @Test
    public void BiFunction_multiple_two_int() {
        BiFunction<Integer, Integer, Integer> concat = (a, b) -> a * b;
        Integer product = concat.apply(3, 4);
        assertEquals(12, product.intValue());
    }
 
    @Test
    public void DoubleFunction_convertDoubleToString_via_lambda() {
        DoubleFunction<String> doubleToString = num -> Double.toString(num);
 
        assertEquals("123.456", doubleToString.apply(123.456));
    }
 
    @Test
    public void DoubleToIntFunction_convertDoubleToInt_via_lambda() {
        DoubleToIntFunction doubleToInt = num -> (int) num;
 
        assertEquals(123, doubleToInt.applyAsInt(123.456));
    }
 
    @Test
    public void DoubleToLongFunction_convertDoubleToLong_via_lambda() {
        DoubleToLongFunction doubleToLongFunc = num -> (long) num;
 
        assertEquals(123789008080l, doubleToLongFunc.applyAsLong(123789008080.456));
    }
 
    @Test
    public void Function_combine_TwoFunctions() {
        Function<LoginUser, String> getUser = LoginUser::getUsertName;
        Function<String, String> toUpper = String::toUpperCase;
 
        Function<LoginUser, String> userNameMustBeUppercase = getUser.andThen(toUpper);
 
        assertEquals("MARY", userNameMustBeUppercase.apply( DataUtil.buildLoginUser("Mary", "pwd123")));
    }
 
    @Test
    public void Function_convertStringToInteger_via_methodReference() {
        Function<String, Integer> convertToWordCount = String::length;
        List<String> words = Arrays.asList("The", "That", "John", "Thanks");
 
        List<Integer> wordsCounts = words.stream().map(convertToWordCount).collect(Collectors.toList());
 
        assertEquals(3, wordsCounts.get(0).intValue());
        assertEquals(4, wordsCounts.get(1).intValue());
        assertEquals(4, wordsCounts.get(2).intValue());
        assertEquals(6, wordsCounts.get(3).intValue());
    }
 
    @Test
    public void IntFunction_convertIntegerToString_via_lambda() {
        IntFunction<String> intToString = num -> Integer.toString(num);
 
        assertEquals("123", intToString.apply(123));
    }
 
    @Test
    public void IntFunction_via_lambda() {
        IntFunction<Integer> powerValue = num -> num * num;
 
        assertEquals(9, powerValue.apply(3).intValue());
    }
 
    @Test
    public void IntToDoubleFunction_convertIntToDouble_via_lambda() {
        IntToDoubleFunction intToDoubleFunc = num -> (double) num;
 
        assertEquals(123, intToDoubleFunc.applyAsDouble(123), 0.1);
    }
 
    @Test
    public void IntToLongFunction_convertIntToLong_via_lambda() {
        IntToLongFunction intToLongFunc = num -> (long) num;
 
        assertEquals(123456, intToLongFunc.applyAsLong(123456));
    }
 
    @Test
    public void LongToDoubleFunction_convertLongToDouble_via_lambda() {
        LongToDoubleFunction longToDoubleFunc = num -> (double) num;
 
        assertEquals(123456, longToDoubleFunc.applyAsDouble(123456), 0.1);
    }
     
    @Test
    public void LongToIntFunction_convertLongToInt_via_lambda() {
        LongToIntFunction longToIntFun = num -> (int) num;
 
        assertEquals(123456, longToIntFun.applyAsInt(123456));
    }
    @Test
    public void stream_map_via_methodReference() {
        Map<String, List<String>> awards = new HashMap<>();
        awards.put("Mary", Arrays.asList("Math", "Spelling Bee"));
        awards.put("Tom", Arrays.asList("Basketball", "Spelling Bee"));
        awards.put("Allen", Arrays.asList("English", "Spelling Bee"));
 
        Function<String, String> convertKeyToUppercase = String::toUpperCase;
 
        List<String> uppercaseKeys = awards.entrySet().stream().map(e -> convertKeyToUppercase.apply(e.getKey()))
                .collect(Collectors.toList());
 
        assertTrue(uppercaseKeys.contains("MARY"));
        assertTrue(uppercaseKeys.contains("TOM"));
        assertTrue(uppercaseKeys.contains("ALLEN"));
    }
 
    @Test
    public void stream_map_with_lambda() {
        List<String> collected = Stream.of("Java", "Rocks").map(string -> string.toUpperCase())
                .collect(Collectors.toList());
 
        assertTrue(collected.contains("JAVA"));
        assertTrue(collected.contains("ROCKS"));
    }
 
    @Test
    public void ToDoubleBiFunction_power_two_int() {
        ToDoubleBiFunction<Integer, Integer> concat = (a, b) -> Math.pow(a, b);
        double powerRet = concat.applyAsDouble(5, 3);
        assertEquals(125.0, powerRet, 0.1);
    }
 
    @Test
    public void ToIntBiFunction_multiple_two_int() {
        ToIntBiFunction<Integer, Integer> concat = (a, b) -> a * b;
        Integer product = concat.applyAsInt(3, 4);
        assertEquals(12, product.intValue());
    }
     
    @Test
    public void ToLongBiFunction_power_two_int() {
        ToLongBiFunction<Integer, Integer> concat = (a, b) -> (long) Math.pow(a, b);
        Long powerRet = concat.applyAsLong(5, 3);
        assertEquals(125, powerRet.intValue());
    }
}

3.2. Predicate

Predicate FI λŠ” ν•˜λ‚˜μ˜ λ§€κ²Œλ³€μˆ˜λ₯Ό λ°›μ•„ 듀이며 Boolean 값을 λ°˜ν™˜ν•œλ‹€. Predicate FI 의 abstract λ©”μ†Œλ“œλŠ” test(Object) 이닀. BiPredicate FI λŠ” λ‘κ°€μ§€μ˜ 맀게 λ³€μˆ˜λ₯Ό 받아듀이며 Boolean 값을 λ°˜ν™˜ν•œλ‹€. Java8 은 λ˜ν•œ μ›μ‹œ 데이터 νƒ€μž…μ„ μœ„ν•œ IntPredicate, LongPredicate, 그리고 DoublePredicate 을 μ œκ³΅ν•œλ‹€.

이번 μž₯μ—μ„œλŠ” λ‹€μŒμ„ μ„€λͺ…ν•˜κΈ° μœ„ν•΄ PredicateTest.java λ₯Ό μƒμ„±ν•œλ‹€.

  • Integerκ°€ 숫자 ν˜•νƒœκ°€ λ§žλŠ”μ§€ μ²΄ν¬ν•œλ‹€.
  • 리슀트의 속성을 Stream - filter(Predicate <T, R>) 을 μ΄μš©ν•˜μ—¬ 필터링 ν•œλ‹€.
  • 두가지 Predicateλ₯Ό ν•˜λ‚˜μ˜ Predicate둜 ν•©μΉœλ‹€.
  • Long 값을 3으둜 λ‚˜λˆŒμˆ˜ μžˆλŠ”μ§€ μ²΄ν¬ν•œλ‹€.
  • Double 값을 값에 맞게 μ²˜λ¦¬λ˜λŠ”μ§€ μ²΄ν¬ν•œλ‹€.
  • 졜초 맀게 λ³€μˆ˜ Integer 값이 λ‘λ²ˆμ§Έ λ§€κ²Œλ³€μˆ˜ 값보닀 큰지 μ²΄ν¬ν•œλ‹€.
  • IntPredicate 와 DoublePredicate 의 μ‚¬μš©λ²•μ„ 보여쀀닀.

PredicateTest.java

 
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
 
import java.util.function.BiPredicate;
import java.util.function.DoublePredicate;
import java.util.function.IntPredicate;
import java.util.function.LongPredicate;
import java.util.function.Predicate;
import java.util.stream.Stream;
 
import org.junit.Test;
 
public class PredicateTest {
 
    @Test
    public void BiPredicate_whichIsBigger() {       
        BiPredicate<Integer, Integer> isBigger = (x, y) -> x > y;
        assertTrue(isBigger.test(5, 4));
        assertTrue(isBigger.negate().test(4, 5));
    }
 
    @Test
    public void DoublePredicate_test_isPositive() {
        DoublePredicate isPositive = x -> x > 0;
        assertTrue(isPositive.test(1.5));
        assertFalse(isPositive.test(-1.7));
    }
 
    @Test
    public void IntPredicate_test_isNagative() {
        IntPredicate isNagative = x -> x < 0;
        assertTrue(isNagative.test(-1));
        assertFalse(isNagative.test(1));
    }
 
    @Test
    public void LongPredicate_test_isDivisibleByThree() {
        LongPredicate isDivisibleBy3 = x -> x % 3 == 0;
 
        assertTrue(isDivisibleBy3.test(12));
        assertFalse(isDivisibleBy3.test(11));
    }
 
    @Test
    public void Predicate_combine_two_predicates() {
        // takes one argument and return a boolean
        Predicate<String> stringIsLongerThanTen = s -> s.length() > 10;
        assertTrue(stringIsLongerThanTen.test("This string is longer than 10"));
        assertFalse(stringIsLongerThanTen.test("short"));
 
        Predicate<String> stringStartWithA = s -> s.startsWith("A");
        assertTrue(stringStartWithA.test("Apple is a fruit"));
 
        Predicate<String> startWithAandLongerThan10 = stringIsLongerThanTen.and(stringStartWithA);
        assertTrue(startWithAandLongerThan10.test("Apple is a fruit which grows everywhere."));
    }
 
    @Test
    public void Predicate_test_integer_isEven() {
        Predicate<Integer> isEven = s -> s % 2 == 0;
        assertTrue(isEven.test(4));
        assertFalse(isEven.test(5));
    }
 
    @Test
    public void stream_filter_via_lambda() {
        Stream.of("Apple", "Pear", "Banana", "Cherry", "Apricot").filter(fruit -> {
            System.out.println("filter:" + fruit);
            return fruit.startsWith("A");
        }).forEach(fruit -> System.out.println("Started with A:" + fruit));
    }
     
}

3.3. Supplier

Supplier FI λŠ” λ§€κ²Œλ³€μˆ˜κ°€ μ—†μœΌλ‚˜ κ²°κ³Ό 값은 λ°˜ν™˜ν•œλ‹€. Supplier FI 의 abstract method λŠ” get() 이닀. 보톡, Java8 μ—μ„œ μ›μ‹œ 데이터 νƒ€μž…μ„ μ‚¬μš©ν•˜κΈ° νŽΈν•˜κ²Œ Interfaceλ₯Ό μ œκ³΅ν•œλ‹€ : IntSupplier, DoubleSupplier, BooleanSupplier, 그리고 LongSupplier.

이번μž₯μ—μ„œλŠ” SupplierTest.java 클래슀λ₯Ό λ‹€μŒμ„ μ„€λͺ…ν•˜κΈ° μœ„ν•΄ μƒμ„±ν•œλ‹€.

  • string 값을 λ°˜ν™˜ν•œλ‹€.
  • true 값을 λ°˜ν™˜ν•œλ‹€.
  • μ΅œλŒ€ Integer 값을 λ°˜ν™˜ν•œλ‹€.
  • μ΅œλŒ€ Long 값을 λ°˜ν™˜ν•œλ‹€.
  • pi 값을 λ°˜ν™˜ν•œλ‹€.

SupplierTest.java

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
 
import java.util.function.BooleanSupplier;
import java.util.function.DoubleSupplier;
import java.util.function.IntSupplier;
import java.util.function.LongSupplier;
import java.util.function.Supplier;
 
import org.junit.Test;
 
public class SupplierTest {
 
    @Test
    public void BooleanSupplier_getAsBoolean() {
        BooleanSupplier booleanSupplier = () -> true;
        assertTrue(booleanSupplier.getAsBoolean());
    }
 
    @Test
    public void DoubleSupplier_getAsDouble() {
        DoubleSupplier pi = () -> Math.PI;
        assertEquals(3.14, pi.getAsDouble(), 0.01);
    }
 
    @Test
    public void IntSupplier_getAsInt() {
        IntSupplier maxInteger = () -> Integer.MAX_VALUE;
        assertEquals(2147483647, maxInteger.getAsInt());
    }
     
    @Test
    public void LongSupplier_getAsLong() {
        LongSupplier maxLongValue = () -> Long.MAX_VALUE;
        assertEquals(9223372036854775807l, maxLongValue.getAsLong());
    }
     
    @Test
    public void Supplier_AString() {
        Supplier<String> message = () -> "Mary is fun";
        assertEquals("Mary is fun", message.get());
    }
}

3.4. Consumer

Consumer FI λŠ” ν•˜λ‚˜μ˜ 맀게 λ³€μˆ˜λ₯Ό κ°€μ§€μ§€λ§Œ 결과값을 λ°˜ν™˜ν•˜μ§€ μ•ŠλŠ”λ‹€. Consumer FI 의 abstract method λŠ” accept(Object) 이닀. 보톡, Java λ˜ν•œ μ›μ‹œ 데이터 νƒ€μž…μ„ μ‚¬μš©ν•˜κΈ° νŽΈν•˜κ²Œ Interfaceλ₯Ό μ œκ³΅ν•œλ‹€: IntConsumer, LongConsumer, DoubleConsumer, BiConsumer, ObjtIntConsumer, ObjLongConsumer, and ObjDoubleconsumer.

주의: XXConsumer FI듀은 μ‚¬μ΄λ“œ 이팩트λ₯Ό ν—ˆμš©ν•˜κ²Œλ” 섀계 λ˜μ–΄ μžˆλ‹€.

이번 μž₯μ—μ„œλŠ” ConsumerTest.java 클래슀λ₯Ό λ‹€μŒμ„ μ„€λͺ…ν•˜κΈ° μœ„ν•΄ μƒμ„±ν•œλ‹€.

  • μ†Œλ¬Έμžλ₯Ό λ³€ν™˜ν•œ 이후 λ¬Έμžμ—΄μ„ 좜λ ₯ν•œλ‹€.
  • λ¬Έμžμ—΄μ„ 좜λ ₯ν•œλ‹€.
  • λ‘κ°€μ§€μ˜ λ¬Έμžμ—΄μ„ 좜λ ₯ν•œλ‹€.
  • μ‚¬λžŒλ“€κ³Ό λ§Œλ‚œ 일 μ΄ν›„μ˜ 년도λ₯Ό 좜λ ₯ν•œλ‹€.
  • ꡬ의 λ‘˜λ ˆλ₯Ό κ³„μ‚°ν•œλ‹€.

ConsumerTest.java

import java.util.Arrays;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.LongConsumer;
import java.util.function.ObjDoubleConsumer;
import java.util.function.ObjIntConsumer;
import java.util.function.ObjLongConsumer;
 
import org.junit.Test;
 
import com.zheng.demo.DataUtil;
import com.zheng.demo.model.Contact;
 
public class ConsumerTest {
 
    @Test
    public void BiConsumer_printout() {
        BiConsumer<String, String> echo = (x, y) -> {
            System.out.println(x);
            System.out.println(y);
        };
        echo.accept("This is first line.", "Here is another line");
    }
 
    @Test
    public void Consumer_convertToLowercase_via_lambda() {
        Consumer<String> convertToLowercase = s -> System.out.println(s.toLowerCase());
        convertToLowercase.accept("This Will convert to all lowercase");
    }
 
    @Test
    public void Consumer_print_prefix() {
        Consumer<String> sayHello = name -> System.out.println("Hello, " + name);
        for (String name : Arrays.asList("Mary", "Terry", "John")) {
            sayHello.accept(name);
        }
    }
 
    @Test
    public void Consumer_print_via_methodreferce() {
        Consumer<String> output = System.out::println;
        output.accept("This will be printed out.");
    }
 
    @Test
    public void DoubleConsumer_printout() {
        DoubleConsumer echo = System.out::println;
        echo.accept(3.3);
    }
 
    @Test
    public void IntConsumer_printout() {
        IntConsumer echo = System.out::println;
        echo.accept(3);
    }
 
    @Test
    public void LongConsumer_printout() {
        LongConsumer echo = System.out::println;
        echo.accept(3l);
    }
 
    @Test
    public void ObjDoubleConsumer_caculate_circle_circumference() {
        ObjDoubleConsumer<Double> circleCircumference = (r, p) -> System.out.println("Circumference: " + 2 * r * p);
 
        circleCircumference.accept(new Double(4.0), Math.PI);
    }
 
    @Test
    public void ObjIntConsumer_alterContactAge() {
        ObjIntConsumer<Contact> addThreeYear = (c, a) -> {
            c.setAge(c.getAge() + a);
            System.out.println("Updated contact" + c);
        };
 
        addThreeYear.accept(DataUtil.buildContact("mzheng", "pwd", 40), 3);
 
    }
 
    @Test
    public void ObjLongConsumer() {
        ObjLongConsumer<String> appendex = (m, l) -> {
            System.out.println("Append " + m + l);
        };
        appendex.accept("test message", 10l);
    }
 
}

3.5. UnaryOperator

UnaryOperator FI λŠ” νŠΉλ³„νžˆ ν”Ό μ—°μ‚°μžμ™€ κ²°κ³Όκ°€ λ™μΌν•œ Function 이닀. UnaryOperator FI 의 abstract method λŠ” apply(Object) 이닀. 보톡, Java8은 μ›μ‹œ νƒ€μž…μ„ μœ„ν•΄ 각각의 클래슀λ₯Ό μ œκ³΅ν•œλ‹€.: IntUnaryOperator, DoubleUnaryOperator, 그리고 LongUnaryOperator.

이번 μž₯μ—μ„œλŠ” UnaryOperatorTest.java 클래슀λ₯Ό λ‹€μŒμ„ μ„€λͺ…ν•˜κΈ° μœ„ν•΄ μƒμ„±ν•œλ‹€.

  • λ¬Έμžμ—΄μ„ λŒ€λ¬Έμž 포멧으둜 λ³€ν™˜ν•œλ‹€.
  • λ¬Έμžμ—΄μ„ λ‹€λ₯Έ λ¬Έμžμ—΄κ³Ό ν•©μΉœλ‹€.
  • μˆ«μžμ—΄ 값을 Double κ°’μœΌλ‘œ λ°˜ν™˜ν•œλ‹€.
  • λ§€κ²Œλ³€μˆ˜μ˜ 값을 연산이후 Long ν˜•κ°’μœΌλ‘œ λ°˜ν™˜ν•œλ‹€.
  • λ§€κ²Œλ³€μˆ˜μ˜ 값을 연산이후 Double ν˜•κ°’μœΌλ‘œ λ°˜ν™˜ν•œλ‹€.

UnaryOperatorTest.java

import static org.junit.Assert.assertEquals;
 
import java.util.function.DoubleUnaryOperator;
import java.util.function.IntUnaryOperator;
import java.util.function.LongUnaryOperator;
import java.util.function.UnaryOperator;
 
import org.junit.Test;
 
public class UnaryOperatorTest {
 
    @Test
    public void UnaryOperator_convertToUppdercase_via_lamdba() {
        UnaryOperator<String> convertToUppercase = msg -> msg.toUpperCase();
         
        String uppString = convertToUppercase.apply("this will be all uppercase");
         
        assertEquals("THIS WILL BE ALL UPPERCASE", uppString);
    }
 
    @Test
    public void UnaryOperator_concatString_via_methodReference() {
        UnaryOperator<String> sayHi = "Hi, "::concat;
         
        String concatString = sayHi.apply("Mary");
         
        assertEquals("Hi, Mary", concatString);
    }
     
    @Test
    public void IntUnaryOperator_doubleIt() {
        IntUnaryOperator doubledIt = x -> x * 2;
        assertEquals(24, doubledIt.applyAsInt(12));
    }
     
    @Test
    public void LongUnaryOperator_squareIt() {
        LongUnaryOperator squareIt = x -> x * x;
        assertEquals(144, squareIt.applyAsLong(12));
    }
     
    @Test
    public void DoubleUnaryOperator_squareIt() {
        DoubleUnaryOperator squareIt = x -> x * x;
        assertEquals(144, squareIt.applyAsDouble(12), 0.1);
    }
 
}

3.6. BinaryOperator

BinaryOperator FI λŠ” νŠΉλ³„νžˆ ν”Ό μ—°μ‚°μžμ™€ κ²°κ³Όκ°€ λ™μΌν•œ Function 이닀. BinaryOperator FI 의 abstract method λŠ” apply(Object) 이닀. 보톡, Java8은 int, long, double 각각의 데이터 νƒ€μž…μœΌλ‘œμ„œ IntBinaryOperator, LongBinaryOperator, 그리고 DoubleBinaryOperator λ₯Ό μ œκ³΅ν•œλ‹€.

이번 μž₯μ—μ„œλŠ” BinaryOperatorTest.java 클래슀λ₯Ό λ‹€μŒμ„ μ„€λͺ…ν•˜κΈ° μœ„ν•΄ μƒμ„±ν•œλ‹€.

  • λ‘κ°œμ˜ 숫자λ₯Ό λ”ν•œλ‹€.
  • λ‹€μ–‘ν•œ 숫자 νƒ€μž…μ„ λ”ν•œλ‹€.
  • 두 숫자의 κ±°λ“­ μ œκ³±μ„ μ²˜λ¦¬ν•œλ‹€.

BinaryOperatorTest.java

import static org.junit.Assert.assertEquals;
 
import java.util.function.BinaryOperator;
import java.util.function.IntBinaryOperator;
import java.util.function.LongBinaryOperator;
import java.util.function.DoubleBinaryOperator;
 
import org.junit.Test;
 
public class BinaryOperatorTest {
 
    @Test
    public void BinaryOperator_add_via_lambda() {
        BinaryOperator<Integer> add = (a, b) -> a + b;
 
        Integer sum = add.apply(10, 12);
 
        assertEquals(22, sum.intValue());
    }
 
    @Test
    public void IntBinaryOperator_add_two_numbers() {
        IntBinaryOperator add2 = (a, b) -> a + b;
 
        int sum = add2.applyAsInt(10, 12);
 
        assertEquals(22, sum);
    }
 
    @Test
    public void LongBinaryOperator_mutiple_two_numbers() {
        LongBinaryOperator add2 = (a, b) -> a * b;
 
        long product = add2.applyAsLong(10, 12);
 
        assertEquals(120, product);
    }
 
    @Test
    public void DoubleBinaryOperator_power_two_number() {
        DoubleBinaryOperator add2 = (a, b) -> Math.pow(a, b);
 
        double powerRet = add2.applyAsDouble(10, 2);
 
        assertEquals(100, powerRet, 001);
    }
 
}

4. Functional Inteface 듀을 μƒνš‘μ— 맞게 μ‚¬μš©

Java8 은 μΈν„°νŽ˜μ΄μŠ€λ₯Ό FI 둜 ν‘œμ‹œν•˜λŠ” μƒˆλ‘œμš΄ μ–΄λ…Έν…Œμ΄μ…˜ @FunctionalInterface λ₯Ό μ œκ³΅ν•œλ‹€. Java μ»΄νŒŒμΌλŸ¬λŠ” ν‘œμ‹œλœ μΈν„°νŽ˜μ΄μŠ€κ°€ ν•˜λ‚˜μ΄μƒμ˜ abstract λ©”μ†Œλ“œλ₯Ό κ°€μ§ˆλ•Œ μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€.

이번 μž₯μ—μ„œλŠ” λ‘κ°œμ˜ FIλ₯Ό μƒμ„±ν•˜μ—¬ Java μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©λ˜λŠ”μ§€ λ‹€μŒμ˜ μ‚¬λ‘€λ‘œ 보여진닀.

  • IntegerCalculator ν΄λž˜μŠ€λŠ” @FunctionalInterface μ–΄λ…Έν…Œμ΄μ…˜μ„ κ°€μ§„λ‹€.
  • GreetFunction ν΄λž˜μŠ€λŠ” @FunctionalInterface μ–΄λ…Έν…Œμ΄μ…˜ 없이 μ²˜λ¦¬λœλ‹€.

4.1. IntegerCaculator

이번 μž₯μ—μ„œλŠ” IntegerCalcuator.java λ₯Ό ν•˜λ‚˜μ˜ λ©”μ†Œλ“œμΈ calcuate 와 ν•¨κ»˜ μƒμ„±ν•œλ‹€.

IntegerCalcuator.java

 
@FunctionalInterface
public interface IntegerCalculator {    
    int caculate(int x, int y); 
}

4.2. GreetingFunction

이번 μž₯μ—μ„œλŠ” GreetingFunction.java λ₯Ό ν•˜λ‚˜μ˜ λ©”μ†Œλ“œμΈ speak 와 ν•¨κ»˜ μƒμ„±ν•œλ‹€. Java μ»΄νŒŒμΌλŸ¬λŠ” ν•΄λ‹Ή 클래슀λ₯Ό @FunctionalInterface μ–΄λ…Έν…Œμ΄μ…˜ 없이 FI 둜 μ·¨κΈ‰ν•œλ‹€.

GreetingFunction.java

public interface GreetingFunction {
    void speak(String message);
}

4.3. Demo

이번 μž₯μ—μ„œλŠ” FPDemo.java 클래슀λ₯Ό λ‹€μŒμ„ μ„€λͺ…ν•˜κΈ° μœ„ν•΄ μƒμ„±ν•œλ‹€.

  • λ‘κ°œμ˜ μˆ«μžκ°€ λ”ν•˜κΈ°, λΉΌκΈ°, κ³±ν•˜κΈ° 계산이 λ˜λŠ”μ§€μ— λŒ€ν•΄ 처리
  • μ–΄λ–€μ‹μœΌλ‘œ μ‚¬λžŒμ„ μ΄ˆλŒ€ν•˜λŠ”μ§€

FPDemo.java

public class FPDemo {
    public static void main(String[] args) {
        GreetingFunction greeting = message -> System.out.println("Hello " + message + "!");
        greeting.speak("Tom");
        greeting.speak("Mary");
 
        caculateTwoNumbers(3, 4);
        caculateTwoNumbers(3, 0);
    }
 
    private static void caculateTwoNumbers(int x, int y) {
        IntegerCalculator add = (a, b) -> a + b;
        IntegerCalculator diff = (a, b) -> a - b;
        IntegerCalculator divide = (a, b) -> (b == 0 ? 0 : a / b);
 
        System.out.println(x + " + " + y + " = " + add.caculate(x, y));
        System.out.println(x + " - " + y + " = " + diff.caculate(x, y));
        System.out.println(x + " / " + y + " = " + divide.caculate(x, y));
    }
}

5. Java8 ν™•μž₯.

Java8 은 Collection 클래슀λ₯Ό sort, max, min λ©”μ†Œλ“œλ₯Ό ν™œμš©ν•˜μ—¬ ν™•μž₯ ν•œλ‹€. ν•΄λ‹Ή λ©”μ†Œλ“œ 듀은 comparator λ₯Ό νŒŒλΌλ©”ν„°λ‘œ Functional interface λ₯Ό μ²˜λ¦¬ν• μˆ˜ μžˆλ‹€.

Java8 Stream 클래슀 API λŠ” 맀게 λ³€μˆ˜λ‘œ Functional interface λ₯Ό λ°›μ•„ λ“€μ΄λŠ” λ©”μ†Œλ“œμΈ map, filter, sorted, min, max, reduce λ₯Ό μ œκ³΅ν•œλ‹€.

5.1. Collections κ³Ό Comparator

Collections ν΄λž˜μŠ€μ™€ Comparator μΈν„°νŽ˜μ΄μŠ€λŠ” Java8 μ—μ„œ ν™•μž₯ λ˜μ—ˆλ‹€. Comparator λŠ” @FunctionalInterface μ–΄λ…Έν…Œμ΄μ…˜μ΄ ν¬ν•¨λ˜μ—ˆλ‹€. λ˜ν•œ Collections의 sort λ©”μ†Œλ“œλŠ” Comparator의 맀게 λ³€μˆ˜λ‘œ 처리 λœλ‹€.

이번 μž₯μ—μ„œλŠ” CollectionsTest.java λ₯Ό λ‹€μŒμ˜ 경우λ₯Ό μ„€λͺ…ν•˜κΈ° μœ„ν•΄ μƒμ„±ν•œλ‹€.

  • μ—°λ½μ²˜λ₯Ό λ‚˜μ΄μˆœμœΌλ‘œ μ •λ ¬ν•œλ‹€.
  • λ¬Έμžμ—΄μ˜ 리슀트λ₯Ό μ •λ ¬ν•œλ‹€.
  • JDK7μ—μ„œμ˜ μ •λ ¬μ²˜λ¦¬μ™€ λΉ„κ΅ν•œλ‹€.

CollectionsTest.java

import static org.junit.Assert.assertEquals;
 
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
 
import org.junit.Test;
 
import com.zheng.demo.dao.ContactDao;
import com.zheng.demo.model.Contact;
 
public class CollectionsTest {
    private ContactDao contDao = new ContactDao();
 
    @Test
    public void Collections_sort_by_contact_age() {
        Comparator<Contact> contactComparator = Comparator.comparing(Contact::getAge);
        List<Contact> contacts = contDao.findAllContacts();
 
        Collections.sort(contacts, contactComparator);
 
        System.out.println("Sorted contact");
        contacts.stream().forEach(System.out::println);
         
        Contact oldertContact = Collections.max(contacts, contactComparator );
        assertEquals(57, oldertContact.getAge());
         
        Contact youngestContact = Collections.min(contacts, contactComparator );
        assertEquals(21, youngestContact.getAge());
 
    }
 
    @Test
    public void Collections_sortWithInferType() {
        List<String> names = Arrays.asList("Allen", "Matt", "Mary", "Megan", "Alex");
        Collections.sort(names, (a, b) -> a.compareTo(b));
        System.out.println("Sorted names: " + names);       
    }
 
    @Test
    public void sortBeforeJava8() {
        List<String> names = Arrays.asList("Allen", "Matt", "Mary", "Megan", "Alex");
     
        Collections.sort(names, new Comparator<String>() {
            @Override
            public int compare(String a, String b) {
                return b.compareTo(a);
            }
        });
    }
 
}

5.2. Stream

Java8 Stream API λŠ” μ†μ„±λ“€μ˜ μ»¬λ ‰μ…˜ μ²˜λ¦¬μ™€ λ°˜λ³΅λ¬Έμ„ μ§κ΄€μ μœΌλ‘œ μ²˜λ¦¬ν•œλ‹€. κ°œλ°œμžλŠ” 더이상 find, search, 객체의 속성을 μ»¬λ ‰μ…˜μ—μ„œ 필터링 ν•˜λŠ”κ²ƒμ„ μ‚¬μš©ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€.

이번 μž₯μ—μ„œλŠ” StreamTest.java 클래슀λ₯Ό λ‹€μŒμ„ μ„€λͺ…ν•˜κΈ° μœ„ν•΄ μƒμ„±ν•œλ‹€.

  • For 반볡문으둜 객체 속성듀을 반볡처리 ν•œλ‹€.
  • Iterator 둜 객체 속성듀을 반볡 μ²˜λ¦¬ν•œλ‹€.
  • Stream API 의 foreach(Consumer<T>) 둜 μ²˜λ¦¬ν•œλ‹€.
  • 객체의 리슀트λ₯Ό νŠΉμ • 객체 μ†μ„±μœΌλ‘œ 필터링 μ²˜λ¦¬ν•œλ‹€.
  • 객체의 리슀트 μ•ˆμ— μžˆλŠ” 객체 속성듀을 λ³€κ²½ν•œλ‹€.
  • 객체의 λ¦¬μŠ€νŠΈμ—μ„œ μ΅œμ†Œκ°’κ³Ό μ΅œλŒ€κ°’μ˜ 값듀을 필터링 ν•˜κ³  λ˜ν•œ μ •λ ¬ν•œλ‹€.

StreamTest.java

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
 
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
 
import org.junit.Before;
import org.junit.Test;
 
public class StreamTest {
    private List<String> userNames;
 
    @Test
    public void search() {
        Predicate<String> startWithA = name -> name.startsWith("a");
        List<String> startWithANames = userNames.stream().filter(startWithA).collect(Collectors.toList());
        assertEquals("aWang", startWithANames.get(0));
    }
 
    @Test
    public void IntStream_sum() {
        int sum = IntStream.of(1, 3, 5, 7, 9).sum();
        assertEquals(25, sum);
    }
 
    @Test
    public void tranform() {
        List<String> uppercaseNames = userNames.stream().map(String::toUpperCase).collect(Collectors.toList());
        assertTrue(uppercaseNames.contains("MZHENG"));
        assertTrue(uppercaseNames.contains("AWANG"));
        assertTrue(uppercaseNames.contains("TCHANG"));
    }
 
    @Test
    public void min() {
        Comparator<String> comparator =  Comparator.comparing(String::length);
        Optional<String> shortestName = userNames.stream().min(comparator );
        assertTrue(shortestName.isPresent());
        assertEquals("aWang", shortestName.get());
         
        Optional<String> longestName = userNames.stream().max(comparator );
        assertTrue(longestName.isPresent());
        assertEquals("mzheng", longestName.get());
         
    }
 
    @Test
    public void print_elelments_via_loop() {
        for (String name : userNames) {
            System.out.println(name);
        }
    }
 
    @Test
    public void print_elements_via_Iterator() {
        Iterator<String> i = userNames.iterator();
        while (i.hasNext()) {
            System.out.println(i.next());
        }
    }
 
    @Test
    public void print_elemetns_via_Stream() {
        // Internal iteration
        userNames.stream().forEach(System.out::println);
    }
 
    @Before
    public void setup() {
        userNames = Stream.of("mzheng", "tChang", "aWang").collect(Collectors.toList());
    }
 
    @Test
    public void sort() {
        List<String> sortedNames = userNames.stream().sorted().collect(Collectors.toList());
        assertEquals("aWang", sortedNames.get(0));
        assertEquals("mzheng", sortedNames.get(1));
        assertEquals("tChang", sortedNames.get(2));
    }
 
}

6. 예제

ν•΄λ‹Ή λΈ”λ‘œκ·Έ κΈ€μ—μ„œ 각각의 Java 사전 μ •μ˜λœ Function interface 듀을 ν…ŒμŠ€νŠΈ ν–ˆμ—ˆκ³ , λ‘κ°œμ˜ 각각 μˆ˜μ •λœ Functiona interface 듀을 ν…ŒμŠ€νŠΈ ν–ˆμœΌλ©°, Comparator, Collections, 그리고 Stream 의 처리λ₯Ό ν™•μΈν–ˆλ‹€. 이번 μž₯μ—μ„œλŠ” μ‹€μ œλ‘œ μ‚¬μš©λ˜λŠ” 사둀λ₯Ό μ„€λͺ… ν•œλ‹€.

ν•΄λ‹Ή 예제의 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œλŠ” λ‹€μŒ λ‘κ°€μ§€μ˜ μš”κ΅¬μ‚¬ν•­μ΄ μžˆλ‹€κ³  κ°€μ •ν•œλ‹€.

  • 데이터 λ² μ΄μŠ€μ—μ„œ μ—°λ½μ²˜λ₯Ό κ°€μ Έμ˜¨λ‹€.
  • 둜그인 μœ μ €μ˜ μ—°λ½μ²˜λ₯Ό λ³€κ²½ν•œλ‹€.

6.1. Contact

이번 μž₯μ—μ„œλŠ” μ„±, 이름, λ‚˜μ΄, μœ μ € 이름, λΉ„λ°€λ²ˆν˜Έλ₯Ό ν¬ν•¨ν•œ Contact.java 클래슀λ₯Ό μƒμ„±ν•œλ‹€.

Contact.java

public class Contact {
 
    private String firstName;
    private String lastName;
    private String userName;
    private String password;
    private int age;
 
    public Contact() {
        super();
    }
 
    public Contact(String firstName, String lastName, String userName, String password, int age) {
        super();
        this.firstName = firstName;
        this.lastName = lastName;
        this.userName = userName;
        this.password = password;
        this.age = age;
    }
 
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
 
    public String getUserName() {
        return userName;
    }
 
    public void setUserName(String userName) {
        this.userName = userName;
    }
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Contact [firstName=" + firstName + ", lastName=" + lastName + ", userName=" + userName + ", password="
                + password + ", age=" + age + "]";
    }
 
}

6.2. LoginUser

이번 μž₯μ—μ„œλŠ” username κ³Ό passwordλ₯Ό ν¬ν•¨ν•œ LoginUser.java 클래슀λ₯Ό μƒμ„±ν•œλ‹€.

LoginUser.java

public class LoginUser {
    private String userName;
    private String password;
 
    public String getUsertName() {
        return userName;
    }
 
    public void setUserName(String userName) {
        this.userName = userName;
    }
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    @Override
    public String toString() {
        return "LoginUser [userName=" + userName + ", password=" + password + "]";
    }
}

6.3. DataUtil

이번 μž₯μ—μ„œλŠ” DataUtil.java 클래슀λ₯Ό μƒμ„±ν•œλ‹€.

DataUtil.java

import java.util.ArrayList;
import java.util.List;
 
public class DataUtil {
    public static List<Contact> getListOfContacts() {
        List<Contact> contacts = new ArrayList<>();
        contacts.add(new Contact("Becky", "Zheng", "bzheng", "pwd1234@", 48));
        contacts.add(new Contact("Alex", "Change", "aChange", "pwd987$", 21));
        contacts.add(new Contact("Caleb", "Wang", "cWang", "pwd2345#", 57));
        return contacts;
    }
 
    public static Contact buildContact(String username, String pwd, int age) {
        Contact cnt = new Contact();
        cnt.setUserName(username);
        cnt.setPassword(pwd);
        cnt.setAge(age);
        return cnt;
    }
     
    public static LoginUser buildLoginUser(String userName, String pwd) {
        LoginUser user = new LoginUser();
        user.setUserName(userName);
        user.setPassword(pwd);
        return user;
    }
     
    public static LoginUser toUser(Contact contact) {
        LoginUser user = new LoginUser();
        user.setPassword(contact.getPassword());
        user.setUserName(contact.getUserName().toUpperCase());
        return user;
    }
}

6.4. ContactDao

이번 μž₯μ—μ„œλŠ” λͺ¨λ“  μ—°λ½μ²˜λ₯Ό μ°ΎλŠ” λ©”μ†Œλ“œλ₯Ό ν¬ν•¨ν•œ ConctactDao.java 클래슀λ₯Ό μƒμ„±ν•œλ‹€.

ContactDao.java

package com.zheng.demo.dao;
 
import java.util.List;
 
import com.zheng.demo.model.Contact;
import com.zheng.demo.model.DataUtil;
 
public class ContactDao {
 
    public List<Contact> findAllContacts(){
        return DataUtil.getListOfContacts();
    }
}

6.4.1. ContactDaoTest

이번 μž₯μ—μ„œλŠ” ContactDaoTest.java 클래슀λ₯Ό μƒμ„±ν•œλ‹€.

ContactDaoTest.java

import static org.junit.Assert.assertEquals;
 
import java.util.List;
 
import org.junit.Test;
 
import com.zheng.demo.model.Contact;
 
public class ContactDaoTest {
 
    private ContactDao testClass = new ContactDao();
 
    @Test
    public void findAllContacts() {
        List<Contact> allContacts = testClass.findAllContacts();
        assertEquals(3, allContacts.size());
    }
}

6.5. Data Mapper

이번 μž₯μ—μ„œλŠ” Contact 클래슀λ₯Ό LoginUser 클래슀둜 λ³€ν™˜ν•˜λŠ” DataMapper 클래슀λ₯Ό μƒμ„±ν•œλ‹€.

DataMapper.java

import com.zheng.demo.model.Contact;
import com.zheng.demo.model.DataUtil;
import com.zheng.demo.model.LoginUser;
 
public class DataMapper {
    public LoginUser toUser(Contact contact) {      
        return DataUtil.toUser(contact);
    }
}

6.5.1. DataMapperTest

이번 μž₯μ—μ„œλŠ” DataMapperTest.java 클래슀λ₯Ό μƒμ„±ν•œλ‹€.

DataMapperTest.java

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
 
import org.junit.Test;
 
import com.zheng.demo.model.Contact;
import com.zheng.demo.model.LoginUser;
 
public class DataMapperTest {
 
    private DataMapper dto = new DataMapper();
 
    @Test
    public void toUser() {
        Contact contact = new Contact("firstName", "lastName", "userName", "password", 40);
        LoginUser user = dto.toUser(contact);
        assertNotNull(user);
        assertEquals("USERNAME", user.getUsertName());
        assertEquals("password", user.getPassword());
    }
}

6.6. LoginUserService

이번 μž₯μ—μ„œλŠ” Contact 클래슀λ₯Ό LoginUser 클래슀둜 λ³€ν™˜ν• μˆ˜ μžˆλŠ” μ—¬λŸ¬κ°€μ§€ 방법이 μ²˜λ¦¬λ˜λŠ” LoginUserService.java 클래슀λ₯Ό μƒμ„±ν•œλ‹€. ν•΄λ‹Ή ν΄λž˜μŠ€λŠ” 각각의 κΈ°λŠ₯이 μžˆλ‹€.

  • Java 8 λ©”μ†Œλ“œ μ°Έμ‘° (μ„Έκ°€μ§€ 포멧이 ν¬ν•¨λœ 버전)
  • Java 8 λžŒλ‹€ ν‘œν˜„μ‹ (μ„Έκ°€μ§€ 포멧이 ν¬ν•¨λœ 버전)
  • Java 8 λžŒλ‹€ ν‘œν˜„μ‹μœΌλ‘œ λͺ…λͺ…λœ κΈ°λŠ₯
  • Java For 반볡문

LoginUserService.java

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
 
import com.zheng.demo.dao.ContactDao;
import com.zheng.demo.model.Contact;
import com.zheng.demo.model.DataUtil;
import com.zheng.demo.model.LoginUser;
 
public class LoginUserService {
 
    ContactDao contactDao = new ContactDao();
    DataMapper dto = new DataMapper();
 
    public List<LoginUser> getAllUser_java8Style_Lambda_1() {
        return contactDao.findAllContacts().stream().map(contact -> {
            LoginUser user = new LoginUser();
            user.setPassword(contact.getPassword());
            user.setUserName(contact.getUserName().toUpperCase());
            return user;
        }).collect(Collectors.toList());
    }
     
    public List<LoginUser> getAllUser_java8Style_Lambda_2() {
        return contactDao.findAllContacts().stream().map(c -> {
            return toUser(c);
        }).collect(Collectors.toList());
    }
     
    public List<LoginUser> getAllUser_java8Style_Lambda_3() {
        return contactDao.findAllContacts().stream().map(c -> toUser(c)).collect(Collectors.toList());
    }
 
    public List<LoginUser> getAllUser_java8Style_methodReference_1() {
        return contactDao.findAllContacts().stream().map(DataUtil::toUser).collect(Collectors.toList());
    }
 
    public List<LoginUser> getAllUser_java8Style_methodReference_2() {
        return contactDao.findAllContacts().stream().map(this::toUser).collect(Collectors.toList());
    }
 
    public List<LoginUser> getAllUser_java8Style_methodReference_best() {
        return contactDao.findAllContacts().stream().map(dto::toUser).collect(Collectors.toList());
    }
 
    public List<LoginUser> getAllUser_java8Style_namedLambda() {
        Function<Contact, LoginUser> convertContactToLoginUser = contact -> {
            return toUser(contact);
        };
        return contactDao.findAllContacts().stream().map(convertContactToLoginUser).collect(Collectors.toList());
    }
 
    public List<LoginUser> getAllUser_loopStyle() {
        List<Contact> allContacts = contactDao.findAllContacts();
        List<LoginUser> allUser = new ArrayList<>();
        for (Contact contact : allContacts) {
            allUser.add(toUser(contact));
        }
        return allUser;
    }
 
    private LoginUser toUser(Contact contact) {
        LoginUser user = new LoginUser();
        user.setPassword(contact.getPassword());
        user.setUserName(contact.getUserName().toUpperCase());
        return user;
    }
 
}

6.6.1. LoginUserServiceTest

이번 μž₯μ—μ„œλŠ” LoginUserServiceTest.java 클래슀λ₯Ό μƒμ„±ν•œλ‹€.

LoginUserServiceTest.java

import static org.junit.Assert.assertTrue;
 
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
 
import org.junit.Test;
 
import com.zheng.demo.model.LoginUser;
 
public class LoginUserServiceTest {
     
    private LoginUserService testService = new LoginUserService();
 
    @Test
    public void getAllUser_java8Style_Lambda_1() {
        List<LoginUser> allusers = testService.getAllUser_java8Style_Lambda_1();
        assertTrue(allusers.size() == 3);
         
        validate(allusers);     
    }
     
    @Test
    public void getAllUser_java8Style_Lambda_2() {
        List<LoginUser> allusers = testService.getAllUser_java8Style_Lambda_2();
        assertTrue(allusers.size() == 3);
         
        validate(allusers);     
    }
     
    @Test
    public void getAllUser_java8Style_Lambda_3() {
        List<LoginUser> allusers = testService.getAllUser_java8Style_Lambda_3();
        assertTrue(allusers.size() == 3);
         
        validate(allusers);     
    }
     
    @Test
    public void getAllUser_java8Style_methodReference_1() {
        List<LoginUser> allusers = testService.getAllUser_java8Style_methodReference_1();
        assertTrue(allusers.size() == 3);
         
        validate(allusers);     
    }
     
    @Test
    public void getAllUser_java8Style_methodReference_2() {
        List<LoginUser> allusers = testService.getAllUser_java8Style_methodReference_2();
        assertTrue(allusers.size() == 3);
         
        validate(allusers);     
    }
     
    @Test
    public void getAllUser_java8Style_methodReference_best() {
        List<LoginUser> allusers = testService.getAllUser_java8Style_methodReference_best();
        assertTrue(allusers.size() == 3);
         
        validate(allusers);     
    }
     
    @Test
    public void getAllUser_java8Style_namedLambda() {
        List<LoginUser> allusers = testService.getAllUser_java8Style_namedLambda();
        assertTrue(allusers.size() == 3);
         
        validate(allusers);     
    }
     
    @Test
    public void getAllUser_loopStyle() {
        List<LoginUser> allusers = testService.getAllUser_loopStyle();
        assertTrue(allusers.size() == 3);
         
        validate(allusers);     
    }
 
    private void validate(List<LoginUser> allusers) {
        Consumer<LoginUser> printOutUser = System.out::println;
        allusers.stream().forEach(printOutUser );
         
        Predicate<LoginUser> foundMary = e -> e.getUsertName().equalsIgnoreCase("bzheng") ;
        List<LoginUser> foundusers = allusers.stream().filter(foundMary ).collect(Collectors.toList());
        assertTrue(foundusers.size() == 1);
    }
}

7. μš”μ•½.

ν•΄λ‹Ή νŠœν† λ¦¬μ–Όμ—μ„œλŠ” 사전에 μ •μ˜λœ functional interface 듀을 μ–΄λ–€μ‹μœΌλ‘œ μ‚¬μš©ν•˜λŠ”μ§€μ— λŒ€ν•΄ λ³΄μ—¬μ€¬μœΌλ©°, λ˜ν•œ 각각 맞좀 Functional interface 의 μ‚¬μš©λ²•μ„ 보여쀬닀.

이후 Stream API λ₯Ό 닀루어 λ³΄μ•˜μœΌλ©°, 이후 μ‹€ μ²˜λ¦¬μ— μ‚¬μš©ν•  수 μžˆλŠ” μ˜ˆμ œλ“€μ„ μ²˜λ¦¬ν–ˆλ‹€.

Functional interface λ₯Ό μ§€μ›ν•˜λŠ” Java 8 은 2014λ…„ 3μ›” 18일에 릴리즈 λ˜μ—ˆλ‹€.
Java λŠ” μ›λž˜ Functional ν”„λ‘œκ·Έλž¨μ„ μ§€μ›ν•˜μ§€ μ•Šμ•˜λ‹€.

Functional programming 은 Function μ—μ„œ κ²°κ³Όλ₯Ό λ¦¬ν„΄ν•˜λŠ”κ²ƒμ— 포컀싱 λ˜μ–΄ 있으며 객체 μ§€ν–₯보닀 μ’€ 더 쒋은 μ„±λŠ₯을 보여쀀닀.

8. 원문

Java 8 Functional Programming Tutorial By Mary Zheng

μ˜μ–΄ 곡뢀λ₯Ό μœ„ν•΄ νΌμ™”μŠ΅λ‹ˆλ‹€. μ €μž‘κΆŒμ΄ λ¬Έμ œκ°€ λœλ‹€λ©΄ μ‚­μ œ ν•˜κ² μŠ΅λ‹ˆλ‹€.

9. λ‹€μš΄λ‘œλ“œ 예제 μ½”λ“œ

ν•΄λ‹Ή μ˜ˆμ œλŠ” 메이븐 ν”„λ‘œμ νŠΈλ‘œ κ΅¬μ„±λ˜μ–΄ 있으며, JUnit test와 사전 μ •μ˜λœ Functional interface와 Collections, Stream API κ°€ ν¬ν•¨λ˜μ–΄ μžˆλ‹€.

GitHub

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages