기능적 자바 소개

1. 개요

이 튜토리얼에서는 몇 가지 예제와 함께 Functional Java 라이브러리에 대한 간략한 개요를 제공합니다.

2. 기능적인 자바 라이브러리

Functional Java 라이브러리는 Java에서 기능 프로그래밍을 용이하게하기위한 오픈 소스 라이브러리입니다. 이 라이브러리는 함수형 프로그래밍에서 일반적으로 사용되는 많은 기본 및 고급 프로그래밍 추상화를 제공합니다.

대부분의 라이브러리 기능은 F 인터페이스를 중심으로합니다 . F 인터페이스는 A 유형 입력을 받고 B 유형의 출력을 반환하는 함수를 모델링합니다 . 이 모든 것은 Java 고유의 ​​유형 시스템 위에 구축됩니다.

3. Maven 종속성

먼저 pom.xml 파일에 필요한 종속성을 추가해야 합니다.

 org.functionaljava functionaljava 4.8.1   org.functionaljava functionaljava-java8 4.8.1   org.functionaljava functionaljava-quickcheck 4.8.1   org.functionaljava functionaljava-java-core 4.8.1 

4. 함수 정의

나중에 예제에서 사용할 수있는 함수를 만들어 보겠습니다.

Functional Java가 없으면 기본 곱셈 방법은 다음과 같습니다.

public static final Integer timesTwoRegular(Integer i) { return i * 2; }

Functional Java 라이브러리를 사용하여이 기능을 좀 더 우아하게 정의 할 수 있습니다.

public static final F timesTwo = i -> i * 2;

위에서 우리 는 Integer 를 입력으로 받고 Integer에 2를 곱한 값을 출력으로 반환하는 F 인터페이스 의 예를 볼 수 있습니다.

다음은 Integer 를 입력 으로 사용하는 기본 함수의 또 다른 예입니다. 이 경우 입력이 짝수인지 홀수인지를 나타내는 부울 을 반환합니다 .

public static final F isEven = i -> i % 2 == 0;

5. 기능 적용

이제 함수가 준비되었으므로 데이터 세트에 적용 해 보겠습니다.

Functional Java 라이브러리는 목록, 세트, ​​배열 및 맵과 같은 데이터를 관리하기위한 일반적인 유형 세트를 제공합니다. 깨달아야 할 핵심은 이러한 데이터 유형은 변경할 수 없다는 것입니다.

또한 라이브러리는 필요한 경우 표준 Java Collections 클래스간에 변환 할 수있는 편리한 기능을 제공 합니다.

아래 예에서는 정수 목록을 정의하고 여기에 timesTwo 함수를 적용 합니다. 또한 동일한 함수의 인라인 정의를 사용하여 map 을 호출 합니다. 물론 결과는 동일 할 것으로 예상합니다.

public void multiplyNumbers_givenIntList_returnTrue() { List fList = List.list(1, 2, 3, 4); List fList1 = fList.map(timesTwo); List fList2 = fList.map(i -> i * 2); assertTrue(fList1.equals(fList2)); }

우리가 볼 수 있듯이 map 은 각 요소의 값이 함수가 적용된 입력 목록의 값인 동일한 크기의 목록을 반환합니다. 입력 목록 자체는 변경되지 않습니다.

다음은 isEven 함수 를 사용하는 유사한 예입니다 .

public void calculateEvenNumbers_givenIntList_returnTrue() { List fList = List.list(3, 4, 5, 6); List evenList = fList.map(isEven); List evenListTrueResult = List.list(false, true, false, true); assertTrue(evenList.equals(evenListTrueResult)); }

때문에 지도의 방법은 목록을 반환, 우리는 그 출력에 다른 기능을 적용 할 수 있습니다. 지도 함수를 호출하는 순서는 결과 출력을 변경합니다.

public void applyMultipleFunctions_givenIntList_returnFalse() { List fList = List.list(1, 2, 3, 4); List fList1 = fList.map(timesTwo).map(plusOne); List fList2 = fList.map(plusOne).map(timesTwo); assertFalse(fList1.equals(fList2)); }

위 목록의 출력은 다음과 같습니다.

List(3,5,7,9) List(4,6,8,10)

6. 함수를 사용한 필터링

함수형 프로그래밍에서 자주 사용되는 또 다른 작업 은 입력받아 몇 가지 기준에 따라 데이터를 필터링하는 것 입니다. 이미 짐작 하셨겠지만 이러한 필터링 기준은 함수의 형태로 제공됩니다. 이 함수는 데이터를 출력에 포함해야하는지 여부를 나타내는 부울을 반환해야합니다.

이제 isEven 함수를 사용하여 filter 메서드를 사용하여 입력 배열에서 홀수를 필터링 해 보겠습니다 .

public void filterList_givenIntList_returnResult() { Array array = Array.array(3, 4, 5, 6); Array filteredArray = array.filter(isEven); Array result = Array.array(4, 6); assertTrue(filteredArray.equals(result)); }

한 가지 흥미로운 관찰은이 예제 에서 이전 예제에서 사용한 것처럼 List 대신 Array 를 사용했으며 함수가 잘 작동 했다는 것입니다 . 함수가 추상화되고 실행되는 방식으로 인해 입력 및 출력을 수집하는 데 사용 된 방법을 알 필요가 없습니다.

이 예에서는 자체 isEven 함수 도 사용 했지만 Functional Java의 자체 Integer 클래스에는 기본 수치 비교를위한 표준 함수도 있습니다.

7. 함수를 사용하여 부울 논리 적용

함수형 프로그래밍에서 우리는 "모든 요소가 특정 조건을 만족하는 경우에만 수행"또는 "적어도 하나의 요소가 특정 조건을 충족하는 경우에만 수행"과 같은 논리를 자주 사용합니다.

Functional Java 라이브러리는 existsforall 메소드 를 통해이 로직에 대한 단축키를 제공 합니다.

public void checkForLowerCase_givenStringArray_returnResult() { Array array = Array.array("Welcome", "To", "baeldung"); assertTrue(array.exists(s -> List.fromString(s).forall(Characters.isLowerCase))); Array array2 = Array.array("Welcome", "To", "Baeldung"); assertFalse(array2.exists(s -> List.fromString(s).forall(Characters.isLowerCase))); assertFalse(array.forall(s -> List.fromString(s).forall(Characters.isLowerCase))); }

위의 예에서는 문자열 배열을 입력으로 사용했습니다. fromString 함수를 호출하면 배열의 각 문자열이 문자 목록으로 변환됩니다. 각 목록에 forall (Characters.isLowerCase)를 적용했습니다 .

짐작 하셨겠지만 Characters.isLowerCase 는 문자가 소문자 인 경우 true를 반환하는 함수입니다. 따라서 문자 목록에 forall (Characters.isLowerCase) 를 적용 하면 전체 목록이 소문자로 구성된 경우 에만 true를 반환 하고 원래 문자열이 모두 소문자임을 나타냅니다.

In the first two tests, we used exists because we only wanted to know whether at least one string was lowercase. The third test used forall to verify whether all strings were lowercase.

8. Handling Optional Values With a Function

Handling optional values in code typically requires == null or isNotBlank checks. Java 8 now provides the Optional class to handle these checks more elegantly, and the Functional Java library offers a similar construct to deal with missing data gracefully through its Option class:

public void checkOptions_givenOptions_returnResult() { Option n1 = Option.some(1); Option n2 = Option.some(2); Option n3 = Option.none(); F
    
      function = i -> i % 2 == 0 ? Option.some(i + 100) : Option.none(); Option result1 = n1.bind(function); Option result2 = n2.bind(function); Option result3 = n3.bind(function); assertEquals(Option.none(), result1); assertEquals(Option.some(102), result2); assertEquals(Option.none(), result3); }
    

9. Reducing a Set Using a Function

Finally, we will look at functionality to reduce a set. “Reducing a set” is a fancy way of saying “rolling it up into one value”.

Functional Java 라이브러리는이 기능을 접기라고 합니다.

요소를 접는다는 의미를 나타내려면 함수를 지정해야합니다. 이에 대한 예 는 배열 또는 목록의 정수를 추가해야 함을 표시 하는 Integers.add 함수입니다.

접을 때 함수가 수행하는 작업에 따라 오른쪽 또는 왼쪽에서 접기를 시작하는지에 따라 결과가 다를 수 있습니다. 이것이 Functional Java 라이브러리가 두 버전을 모두 제공하는 이유입니다.

public void foldLeft_givenArray_returnResult() { Array intArray = Array.array(17, 44, 67, 2, 22, 80, 1, 27); int sumAll = intArray.foldLeft(Integers.add, 0); assertEquals(260, sumAll); int sumEven = intArray.filter(isEven).foldLeft(Integers.add, 0); assertEquals(148, sumEven); }

첫 번째 foldLeft는 단순히 모든 정수를 더합니다. 두 번째는 먼저 필터를 적용한 다음 나머지 정수를 추가합니다.

10. 결론

이 기사는 Functional Java 라이브러리에 대한 간략한 소개입니다.

항상 그렇듯이 기사의 전체 소스 코드는 GitHub에서 사용할 수 있습니다.