요약
내가 자유 롭을 때, 나는 JVM에서 실행되는 그루비와 스칼라를 배우는 데 시간이 걸렸으며, 이전 버전의 Java보다 훨씬 신중하게 Null을 다루는 것을 발견했습니다. Java 8에서 옵션은 기능 프로그래밍 NULL 처리를위한 매우 우아한 솔루션을 제공합니다. 이 기사는 Java에서 NULL의 오랜 잘못된 취급을 설명하고 Java 기능 프로그래밍을 구현하기 위해 선택 사항을 소개합니다.
그 시절에 우리를 괴롭힌 널
Java World에는 전설이 있습니다. Null 포인터 예외를 진정으로 이해할 때만 자격을 갖춘 Java 개발자로 간주 될 수 있습니다. Java 캐릭터 경력에서 우리는 매일 다양한 널 처리를 만날 것입니다. 우리는 매일 반복적으로 다음과 같은 코드를 쓸 수 있습니다.
if (null! = obj1) {if (null! = obje2) {// 뭔가}}약간의 비전이 있다면 Javaer는 예쁜 일을하고 Null을 판단하는 방법을 찾을 것입니다.
부울 checknotnull (object obj) {return null == obj? 거짓 : 사실; } void do () {if (checknotnull (obj1)) {if (checknotnull (obj2)) {// do do}}}그런 다음 질문이 다시 발생합니다. 널이 빈 문자열을 나타내면 ""는 무엇을 의미합니까?
그러면 관성 사고가 우리에게 말합니다. ""그리고 Null은 모두 빈 문자열 코드입니까? 나는 단순히 null 값을 업그레이드했습니다.
부울 checknotblank (object obj) {return null! = obj && "". 사실 : 거짓; } void do () {if (checknotblank (obj1)) {if (checknotnull (obj2)) {// do do}}}시간이 있다면 현재 프로젝트에 얼마나 많은 코드를 작성했는지 또는 과거 코드와 위의 코드와 유사한 내용을 확인할 수 있습니다.
질문에 대해 진지하게 생각했는지 궁금합니다. 널은 무엇을 의미합니까?
회상하면, 우리는 이전 그래밍 경력에서 java.lang.nullpointerexception 예외를 몇 번이나 만났습니까? NullPointerException은 캡처 할 필요가없는 runtimeexception 레벨 예외입니다. 실수로 처리하면 생산 로그에서 NullPointerException으로 인한 다양한 예외 스택 출력이 종종 나타납니다. 그리고이 예외 스택 정보를 바탕으로 문제의 원인을 전혀 찾을 수 없습니다. 왜냐하면 NullPointerException이 발생한 곳이 아니기 때문에 문제가 발생했습니다. 우리는이 널이 생성 된 위치를 알아 내기 위해 더 깊이 가야하며, 현재 로그를 추적 할 수 없습니다.
때로는 널 값이 생성되는 장소가 종종 우리 자신의 프로젝트 코드에 있지 않다는 것이 훨씬 더 비극적입니다. 이것은 더 창피한 사실을 가지고 있습니다. 우리가 다양한 품질의 다양한 타사 인터페이스를 호출 할 때 인터페이스가 우연히 널을 반환하는지 알기가 어렵습니다 ...
NULL의 이전인지 문제로 돌아갑니다. 많은 Javaers는 Null이 "아무것도"또는 "가치가 존재하지 않는다"는 것을 의미한다고 생각합니다. 이 관성 사고에 따르면, 우리의 코드 로직은 다음과 같습니다. 당신은 내 인터페이스를 호출하고 당신이 나에게 제공하는 매개 변수에 따라 해당 "값"을 반환합니다. 이 조건이 해당 "값"을 찾을 수 없다면 물론 "사물"이 없다는 Null을 반환합니다. 매우 전통적인 표준 Java 코딩 스타일로 작성된 다음 코드를 살펴 보겠습니다.
클래스 myentity {int id; 문자열 이름; 문자열 getName () {return name; }} // mainpublic 클래스 테스트 {public static void main (String [] args) 최종 myentity myentity = getmyentity (false); System.out.println (myentity.getName ()); } private getmyentity (boolean issuc) {if (issuc) {return new myentity (); } else {return null; }}}이 코드는 매우 간단하며 일일 비즈니스 코드는 이보다 훨씬 더 복잡하지만 실제로이 루틴에 따라 많은 수의 Java 코드가 작성됩니다. 상품을 사용하는 방법을 아는 사람들은 결국 널리 퍼진을 던질 것이라고 한 눈에 볼 수 있습니다. 그러나 비즈니스 코드를 작성할 때, 우리는이 가능한 NULL을 다루는 것을 거의 생각하지 않습니다 (아마도 API 문서는 매우 명확하게 작성되었을 수도 있고 어떤 경우에는 NULL을 반환 할 것입니다. 그러나 코드를 작성하기 전에 API 문서를 신중하게 읽을 것입니까?), 특정 단계의 테스트 단계에 도달 할 때까지 갑자기 판단력을 발휘할 때까지 우리는 널리 알려진 가치가 다시 나타났습니다.
// MainPublic 클래스 테스트 {public static void main (String [] args) 최종 myentity myentity = getmyentity (false); if (null! = myentity) {system.out.println (myentity.getName ()); } else {system.out.println ( "error"); }}}지난 몇 년 동안주의 깊게 생각해보십시오. 우리 모두는 이것을 했습니까? 테스트 단계까지 일부 널 문제를 발견 할 수없는 경우, 문제는 이제 복잡하고 잘 구조화 된 비즈니스 코드에서 몇 개의 널이 제대로 처리되지 않습니까?
Null을 다룰 때 프로젝트의 성숙도와 엄격함이 종종 볼 수 있습니다. 예를 들어, Guava는 JDK1.6 이전에 우아한 널 처리 방법을 제공하여 기술의 깊이를 보여줍니다.
유령 널은 우리가 진행하는 것을 방해합니다
전통적인 객체 지향 개발에 중점을 둔 Javaer라면 NULL로 인한 다양한 문제에 익숙 할 수 있습니다. 그러나 몇 년 전, 위대한 하나님은 Null이 구덩이라고 말씀하셨습니다.
Tony Hall (이 사람이 누구인지 알지 못합니다. (일반적인 의미는 다음과 같습니다.
그런 다음 다른 문제가 어떤 문제를 소개 할 것인지 살펴 보겠습니다.
다음 코드를 확인하십시오.
문자열 주소 = person.getCountry (). getProvince (). getCity ();
기능적 언어 (Haskell, Erlang, Clojure, Scala 등)를 연주했다면 위의 글은 매우 자연스러운 글쓰기 방식입니다. 물론 위의 작문 방법은 Java를 사용하여 구현할 수 있습니다.
그러나 가능한 모든 null 예외를 완벽하게 처리하려면이 우아한 기능 프로그래밍 패러다임을 이것으로 변경해야합니다.
if (person! = null) {country country = person.getCountry (); if (country! = null) {province province = country.getProvince (); if (province! = null) {address = province.getCity (); }}}순간적으로, 고품질 기능 프로그래밍 Java8은 10 년 전으로 돌아 왔습니다. 이러한 중첩 된 판단은 여전히 사소한 일이며 코드의 양이 증가하고 부적절합니다. 더 많은 일이 발생할 가능성이 높습니다 : 대부분의 경우, 사람들은 발생할 수있는 귀무를 판단하는 것을 잊어 버릴 것입니다.
층별로 중첩 된 NULL 처리 섹션은 오랫동안 비판을받은 전통적인 Java의 일부입니다. 초기 Java 버전을 깨달음 언어로 사용하는 경우, 널-> 반환의 냄새는 오랫동안 당신에게 영향을 미칩니다 (외국인 커뮤니티에서 기억하십시오 : 엔터티 중심 개발).
Java 기능 프로그래밍을 구현하기 위해 선택 사항을 사용합니다
좋아, 모든 종류의 문제에 대해 이야기 한 후, 우리는 새로운 시대에 들어갈 수 있습니다.
Java SE 8 버전이 출시되기 오래 전에 다른 유사한 기능 개발 언어에는 자체 솔루션이있었습니다. Groovy의 코드는 다음과 같습니다.
문자열 버전 = computer? .getSoundCard ()?. getUSB ()?
Haskell은 아마도 유형 클래스 식별자를 사용하여 NULL 값을 처리합니다. 다중-파라디 그 (paradigm) 개발 언어로 알려진 Scala는 NULL을 포장 및 처리하기위한 것과 유사한 옵션을 제공합니다.
Java8은 기능적 프로그래밍의 널 문제를 처리하기 위해 java.util.optional <t>를 소개합니다. 옵션 <t>의 처리 아이디어는 Haskell 및 Scala의 처리 아이디어와 유사하지만 몇 가지 차이점이 있습니다. Java 코드의 다음 예를 살펴 보겠습니다.
공개 클래스 테스트 {public static void main (String [] args) {Final String Text = "Hallo World!"; 옵션 .ofNullable (text) // 선택적 shell.map (test :: print) .map (test :: print) .ifpresent (system.out :: println); 옵션 .ofnullable (text) .map (s-> {System.out.println (s); return s.substring (6);}) .map (s-> null) // return null .ifpresent (system.out :: println); } // str [5] 이후 문자열을 인쇄하고 가로 채 웁니다. 개인 정적 문자열 print (String Str) {System.out.println (str); Return str.substring (6); }} // consol output // num1 : hallo world! // num2 : world! // num3 : // num4 : hallo world!(JDK8을 설치 해야하는 경우 위의 코드를 IDE에 복사 할 수 있습니다.)
위 코드에서 두 가지 옵션이 생성되며 구현 된 기능은 기본적으로 동일합니다. 둘 다 스트링 쉘로 옵션을 사용하여 문자열을 자릅니다. 처리 중에 널 값이 발생하면 처리는 더 이상 계속되지 않습니다. S-> NULL이 두 번째 선택 사항에 나타나면 후속 IFPRESENT가 더 이상 실행되지 않는다는 것을 알 수 있습니다.
출력 // num3 :에주의를 기울이십시오. 즉, ""캐릭터가 널이 아닌 출력임을 의미합니다.
선택 사항은 코드 수정과 같은 다양한 상황을 처리하기위한 풍부한 인터페이스를 제공합니다.
공개 클래스 테스트 {public static void main (String [] args) {Final String Text = "Hallo World!"; System.out.println (소문자 (텍스트)); // 메소드 하나의 소문자 (null, system.out :: println); // 메소드 2} 개인 정적 문자열 소문자 (string str) {return optional.ofnullable (str) .map (s-> s.tolowscase ()). Map ( "world", "java") } private static void 소문자 (String Str, 소비자 <문자열> 소비자) {소비자 (소문자); }} // output // Hallo Java! // nan이런 식으로 문자열을 동적으로 처리 할 수 있습니다. 값이 언제든지 널 인 것으로 밝혀지면 Orelse를 사용하여 사전 설정 기본 "NAN"을 반환합니다.
일반적으로 데이터 구조를 선택 사항으로 래핑 한 다음 언제든지 나타날 수있는 널에 대해 걱정하지 않고 기능적으로 처리 할 수 있습니다.
person.getCountry (). getProvince (). getCity () 앞에서 언급 한 방법을 살펴 보겠습니다.
첫 번째 방법은 이전 엔티티를 변경하지 않는 것입니다.
import java.util.optional; public class test {public static void main (string [] args) {system.out.println (옵션.ofnullable (new person ()) .map (x-> x.country) .map (x-> x.provinec) .map (x-> x.city) .map (x-> x.name). .orelse ( "Unkonwn")); }} Class Person {Country Country;} Class Country {Province Provisionec;} Class Province {City City;} Class City {문자열 이름;}여기서 옵션은 매번 쉘이 반환 될 때 사용됩니다. 특정 위치가 NULL을 반환하면 "Unkonwn"을 받게됩니다.
두 번째 방법은 선택 사항에서 모든 값을 정의하는 것입니다.
import java.util.optional; public class test {public static void main (string [] args) {system.out.println (new person () .country.flatmap (x -> x.provinec) .flatmap (provemins :: getcity) .flatmap (x-> x.name) .orelse ( "unkonwn"); }} 클래스 개인 {옵션 <country> country = 옵션 .empty.empty ();} 클래스 국가 {옵션 <지방> provisionc;} class province {옵션 <city> city; 옵션 <city> getCity () {// for :: return City; }} Class City {옵션 <문자열> 이름;}첫 번째 방법은 변경없이 기존 Javabeans, Entity 또는 Poja와 부드럽게 통합 될 수 있으며 타사 인터페이스 (예 : 스프링 콩)에보다 쉽게 통합 될 수 있습니다. 첫 번째 선택 방법이 기본 방법으로 사용되는 것이 좋습니다. 결국, 팀의 모든 사람이 선택 사항으로 각 GET/세트의 목적을 이해할 수있는 것은 아닙니다.
옵션은 또한 데이터를 필터링하기위한 필터 방법을 제공합니다 (실제로 Java 8의 스트림 스타일 인터페이스는 필터 방법을 제공합니다). 예를 들어, 과거에 우리는 그 값이 존재하고 해당 처리를 작성했다고 판단했습니다.
if (province! = null) {City City = province.getCity (); if (null! = city && "Guangzhou".Equals (city.getName ()) {system.out.println (city.getName ());} else {system.out.println ( "unkonwn");}}이제 우리는 그것을 수정할 수 있습니다
옵션 .ofNullable (Province) .map (x-> x.city) .filter (x-> "Guangzhou".Equals (x.getName ())) .map (X-> X.Name) .ORELSE ( "UNKONW");
이 시점에서 기능적 프로그래밍 소개는 선택 사항을 사용하여 완료됩니다. 위에서 언급 한 방법 외에도 옵션은 OrelSeget, OrelSethrow 등의 더 많은 요구를 기반으로하는 방법을 제공합니다. OrelSeget은 NULL 값으로 인해 NULL 포인터 예외를 던지고 OrelsetHrow는 NULL이 발생할 때 사용자 정의 예외를 던집니다. API 문서를보고 모든 방법에 대해 자세히 알아볼 수 있습니다.
마지막에 작성되었습니다
선택 사항은 Java 기능 프로그래밍의 빙산의 일각입니다. Java8 기능 프로그래밍의 효과를 진정으로 이해하려면 Lambda, Stream 및 Functioninterface와 같은 기능을 결합해야합니다. 원래 일부 선택적 소스 코드 및 작동 원리를 소개하고 싶었지만 선택 사항 자체에는 코드가 거의없고 API 인터페이스가 많지 않습니다. 당신이 그것에 대해 신중하게 생각한다면, 할 말이없고 그것을 생략 할 것입니다.
선택 사항은 우아하지만 개인적으로 효율성 문제가 있다고 생각하지만 아직 확인되지 않았습니다. 누군가가 데이터가 있으면 알려주십시오.
나는 "기능적 프로그래밍 지지자"가 아닙니다. 팀 관리자의 관점에서, 모든 작은 학습 어려움이 증가 할 때, 인사 사용 비용과 팀 상호 작용이 더 높아질 것입니다. LISP와 마찬가지로 LISP는 C ++보다 코드가 30 배 적을 수 있으며 개발이 더 효율적일 수 있지만 국내 기존 IT 회사가 실제로 LISP를 사용하여 프로젝트를 수행하는 경우 LISP를 사용하는 사람들을 얻는 데 드는 비용은 얼마입니까?
그러나 나는 모든 사람들이 기능 프로그래밍의 아이디어를 배우고 이해하도록 격려합니다. 특히 Java에 의해 침략되었지만 여전히 Java8이 가져올 변화가 무엇인지 여전히 알지 못하는 개발자는 Java8이 좋은 기회입니다. 또한 현재 프로젝트에 새로운 Java8 기능을 도입하는 것이 좋습니다. 오랫동안 협력하는 팀과 고대 프로그래밍 언어는 지속적으로 새로운 활력을 주입해야합니다. 그렇지 않으면 발전하지 않으면 후퇴 할 것입니다.
위의 것은 Java 옵션 정보 모음입니다. 우리는 향후 관련 정보를 계속 추가 할 것입니다. 이 웹 사이트를 지원 해주셔서 감사합니다!