[Java] Java8, 람다 표현식(Lambda expressions)

많은 프로그래밍 언어에서 람다 표현식은 한번 사용하고 버릴 함수를 정의하기 위한 용도로 많이 사용됩니다. 물론 이 람다 표현식에 의해 만들어진 함수를 변수에 담아 두번 이상 사용할 수도 있지만… 어찌되었든, 람다는 빠르게 함수를 만들어 사용하고는, 버리는 용도로 사용합니다.

Java 8에서 람다 표현식을 지원하고 있는데요. 문자열 요소를 가지는 리스트를 정렬하는 예를 통해 람다 표현식을 살펴 보겠습니다. 정렬할 문자열 리스트로 사용할 names 객체 변수는 아래와 같습니다.

List names = 
    Arrays.asList("검소", "겸손", "명상", "욕심", "탐하는 마음", "경솔", "교만", "어질지못함");

람다 표현식이 아닌 우리가 이미 알고 있는 방식의 코드는 아래와 같습니다.

Collections.sort(names, new Comparator() {
    @Override
    public int compare(String a, String b) {
        return -b.compareTo(a);
    }
});

위의 Collections의 sort 함수의 두번째 인자에 1회용 목적으로 익명 객체를 생성해 던져주고 있습니다. 이 익명 객체를 생성하기 위한 인터페이스가 단 하나의 매서드에 대한 정의를 필요로 합니다. 이를 람다 표현식으로 바꾸면 아래와 같습니다.

Collections.sort(names, (String a, String b) -> {
    return -b.compareTo(a);
});

람다식을 컴파일로가 해석할 때 어떤 타입의 어떤 매서드를 정의하는지를 자동으로 추론해 줍니다. (염병할, 나보다 더 똑똑해!) 위의 람다식을 보면 함수의 코드가 한줄이므로 아래처럼 더 줄일 수 있습니다.

Collections.sort(names, (String a, String b) ->  -b.compareTo(a));

코드가 한줄이므로 {}을 제거할 수 있고, return 키워드를 제거해도 반환한다라는 개념을 이미 추론을 통해 파악하고 있습니다. (이제 니가 코딩해라, 난 뭐하냐?) 충분히 줄였다 싶을 람다 표현식을 더 줄일 수 있는데요. 어차피 어떤 함수를 람다식으로 정의하는지를 알고 있다면 해당 함수의 타입을 명시적으로 언급하지 않아도 추론이 가능할 것으므로 아래처럼 더 최적화할 수 있습니다.

Collections.sort(names, (a, b) -> -b.compareTo(a));

(이젠 나도 모르겠을 암호 코드.. ㅜ_ㅜ) 위의 내용은 람다식의 일부입니다. 람다에 좀더 깊이 들어가면.. 깜짝 놀라거임.. -O-;

jQuery 선택자 컨닝 페이퍼 2

filter

filter 함수는 이미 선택된 항목에 대해서 다시 한번 더 선택을 하고자 할 때 사용합니다.

$('h1').css('background', '#ff0000').filter(':even').css({'color', '#00ff00');

인자를 함수 객체를 던져 처리하는 형태도 가능하며, 아래의 예는 h1 요소 중 짝수번째 요소들에 대한 처리입니다.

$('h1').filter(
    function(index) {
        return (index % 2) == 0;
    }
).css({'color', '#00ff00'});

eq, first, last

요소에 대한 위치 순서로 선택하는 선택자 함수입니다.

$('p').eq(3).css('color', '#00ff00'); // 4번째 요소
$('p').first().css('color', '#ff0000'); // 첫번째 요소
$('p').last().css('color', '#0000ff'); // 마지막 요소
$('p'').eq(-1).css('color', '#ff00ff'); // 끝에서 첫번째 요소

add

이미 선택된 요소들에 다른 요소를 추가하는 함수입니다.

$('p').css('color', '#ff0000').add('span').css('background', '#ffff00');

is

해당 요소가 선택 조건에 맞는지를 검사합니다.

$('h1').each(
    function() {
        if($(this).is('.a')) {
            $(this).css('color', '#ff0000');
        }
    }
);

find

특정 태그 또는 클래스를 갖는 요소를 선택하는 함수입니다.

var doc = $('

...

...

...
'); doc.find('p').each( function(index) { $(this).css('background', '#0000ff'); } );

jQuery 선택자 컨닝 페이퍼

늦깍이에 웹 개발의 험난한 파도 속에 허욱적 대고 있는 요즘.. jQuery에서 가장 많이 사용하는 선택자가 까마귀 고기로 보여 컨닝 페이퍼 만들어 봅니다.

전체 선택자

$('*').css('color', 'red');

Tag 선택자

$('h1').css('color', 'orange');

ID 선택자

$('#abc').css('color', 'orange');

여러 개의(OR 조건) 선택자

$('h1, p, #abc').css('color', 'orange');

class 선택자

$('.item').css('color', 'black');

AND 조건 선택자

$('.item.abc').css('color', 'black');

자식 선택자

$('div > p').css('color', 'black');

후손 선택자

$('div p').css('color', 'black');

속성 선택자

$('h1[tt').val('good'); // 속성을 가지는 것 선택
$('h1[tt=aa').val('good'); // 속성값 일치하는 것 선택
$('h1[tt~=aa').val('good'); // 속성값에 단어로써 포함하는 것 선택
$('h1[tt^=aa').val('good'); // 속성값의 시작에 일치하는 것 선택
$('h1[tt$=aa').val('good'); // 속성값의 끝에 일치하는 선택
$('h1[tt*=aa').val('good'); // 속성값에 포함하는 것 선택

input tag 중 특정 type 선택자

$(':button').val("BTN");
$('.a:button').attr("disabled", true);

input tag 중 특정 상태 선택자

$('.a:checked').val('good'); // checked된 input 요소
$('.a:disabled').val('good'); // 비활성화된 input 요소
$('.a:enabled').val('good'); // 활성화된 input 요소
$('.a:focus').val('good'); // 포커스 대상 input 요소
$('.a:input').val('good'); // input, textarea, button, select 요소
alert( $('.a > option:selected').val() ); // class 'a'를 가진 select 요소 자식 중 선택된 option 요소

jQuery, 자주 묻는 질문들

(문제) class나 ID를 통해 어떻게 항목을 선택할 수 있나요?

아래의 코드는 ID가 #myDivId인 항목을 선택합니다.

$('#myDivId');

아래는 myCssClass라는 class 이름을 갖는 요소를 선택합니다.

$('.myCssClass');

(문제) 이 DOM 요소를 가지고 있을때, 이를 이용해 요소를 어떻게 선택하나요?

아래의 코드는 ID가 foo인 DOM 요소를 가지고, 이 요소에 포함된 모든 요소를 선택하고 있습니다.

var myDomElement = document.getElementById('foo');
$(myDomElement).find('a');

(문제) 특정 class가 지정되어져 있는 요소인지 확인은 어떻게 하나요?

아래의 코드처럼 hasClass를 사용하면 됩니다.

$( "div" ).click(function() {
    if ( $( this ).hasClass( "protected" ) ) {
        $( this )
            .animate({ left: -10 })
            .animate({ left: 10 })
            .animate({ left: -10 })
            .animate({ left: 10 })
            .animate({ left: 0 });
    }
});

또한 아래처럼 요소의 상태 확인이 가능한 is 함수를 사용해서도 가능합니다.

if ( $( "#myDiv" ).is( ".pretty.awesome" ) ) {
    $( "#myDiv" ).show();
}

is 함수는 선택된 요소가 숨김 상태인지를 다음처럼 확인할 수 있습니다.

if ( $( "#myDiv" ).is( ":hidden" ) ) {
    $( "#myDiv" ).show();
}

(문제) 선택 요소가 있는지 확인은 어떻게 하나요?

선택자로 얻은 결과에 대해 .length 속성으로 아래처럼 확인할 수 있습니다. length 속성은 선택자에 의해 몇개의 요소가 선택되었는지에 대한 개수를 반환합니다.

if ( $( "#myDiv" ).length ) {
    $( "#myDiv" ).show();
}

(문제) 토글(toggled)되어진 요소의 상태를 어떻게 결정할 수 있나요?

요소가 숨겨져 있는지에 확인하는 것은 :visible과 :hidden 선택자를 사용해 파악이 가능하다.

var isVisible = $( "#myDiv" ).is( ":visible" );
var isHidden = $( "#myDiv" ).is( ":hidden" );

가시성에 기반해 요소에 대한 간단한 조작을 하고자 한다면, 단지 선택자에서 :visible이나 :hidden을 사용합니다. 아래이 코드를 보시기 바랍니다.

$( "#myDiv:visible" ).animate({
    left: "+=200px"
}, "slow" );

(문제) 폼 요소에 대해 비활성화/활성화는 어떻게 하나요?

아래의 코드처럼 prop 함수를 사용해 폼 요소를 활성화 하거나 비활성화 할 수 있습니다.

// Disable #x
$( "#x" ).prop( "disabled", true );

// Enable #x
$( "#x" ).prop( "disabled", false );

(문제) 체크박스 또는 라디오버튼에 대한 체크나 언체크는 어떻게 하나요?

아래의 코드처럼 prop 함수를 사용해 체크 여부를 결정할 수 있습니다.

// Check #x
$( "#x" ).prop( "checked", true );

// Uncheck #x
$( "#x" ).prop( "checked", false );

(문제) 선택된 option의 텍스트 값은 어떻게 얻나요?

선택 요소는 일반적으로 얻을 수 있는 2가지 값이 있습니다. 첫번째는 서버로 보내지는 값이며, 아래처럼 간단히 얻을 수 있습니다.

$( "#myselect" ).val();
// => 1

두번째는 선택된 요소의 텍스트 값인데요. 예를들어 아래와 같은 코드와 같다고 합시다.


아래의 코드를 통해 선택된 option의 텍스트 값을 얻을 수 있습니다.

$( "#myselect option:selected" ).text();
// => "Mr"

(문제) 10개의 항목 리스트 중 3번째 요소의 텍스트값을 변경하기는?

:eq() 선택자 또는 eq 함수를 사용해 원하는 항목을 선택할 수 있습니다. 아래는 eq 함수를 사용한 경우입니다.

var thirdLink = $( this ).find( "li a" ).eq( 2 );
var linkText = thirdLink.text().replace( "foo", "bar" );
thirdLink.text( linkText );

(문제) jQuery 객체로부터 Native DOM 요소를 어떻게 얻나요?

선택자에 의한 jQuery 객체는 1개 이상의 DOM 요소를 배열처럼 감싼 객체입니다. 이 jQuery 객체에 대한 실제 DOM 요소에 대한 참조를 얻기 위한 방법은 2가지입니다. 첫번째는 배열 표기법으로 아래와 같습니다.

$( "#foo" )[ 0 ]; // document.getElementById( "foo" )와 동일한 코드

2번째 방법은 get 함수로 다음과 같습니다. (첫번째 방법보다 느림)

$( "#foo" ).get( 0 ); 

만약 get 함수에 인자를 지정하지 않고 호출하면, DOM 요소의 실제 배열을 반환합니다.

jQuery의 유틸리티 함수

jQuery의 플러그인 기능 중에 유틸리티 성격의 플러그인을 정리해 봅니다. 정리해 놓으면 딱 필요할때 익숙하게 사용할 수 있겠지요.

먼저 문자열 앞뒤의 공백 문자를 제거해 주는 코드입니다.

var s = '   You are, you will be good.      ';
s = $.trim(s);

다음은 배열의 값이나 객체의 키-값들을 순회하는 each 함수이며, 예제 코드는 아래와 같습니다.

$.each(['foo', 'bar', 'baz'], function (i, v) {
    alert(i + " : " + v);
});

$.each({ foo: 'bar', baz: 'bim' }, function (k, v) {
    alert(k + ' : ' + v);
});

그리고 어떤 값이 배열에 속해 있는지를 검사하는 플러그인입니다.

var myArray = [1, 2, 3, 4, 5];
if ($.inArray(4, myArray) !== -1) {
    alert('found.');
}

다음은 어떤 객체에 또 다른 객체의 키-값을 복사해 주는 플러그인입니다. $.extend의 첫번째 인자는 복사가 되어 값이 저장될 대상 객체입니다. 그리고 두번째 이후의 인자는 복사될 키-값을 담고 있는 객체들입니다. 아래의 코드는 secondObj의 키-값을 firstObj에 복사해 주는 코드인데요. 결국 firstObj.foo는 secondObj.foo의 값으로 변경됩니다. $.extend는 첫번째 인자를 반환하므로 newObject === firstObj는 true입니다.

var firstObj = { foo: 'bar', a: 'b' };
var secondObj = { foo: 'baz' };
var newObject = $.extend(firstObj, secondObj);

alert(firstObj.foo);

if (newObject === firstObj) {
    alert('equal');
}

다음 코드는 함수 호출시 내부의 this를 개발자가 의도한 객체로 하여 함수를 호출하도록 하는 플러그인입니다. 아래의 코드에서 myFunction는 전역 객체인 Window의 소유로 이 함수를 그대로 호출하면 함수 내부에서 this는 Window 객체가 됩니다. 그러나 12번 코드를 통해 myFunction 함수에 대한 내부 this를 myObject로 변경해주는 함수로 myProxyFunction를 생성하고 있습니다. 실제로 이 myProxyFunction를 13번 코드처럼 그대로 호출하면 함수 내부의 this는 myObject가 됩니다. JavaScript의 이벤트 리스너 함수에서 this 객체가 다소 혼란스러울 때가 있습니다. 이 혼란의 시기에 이 플러그인이 해결점이 될 수 있겠습니다.

var myFunction = function () {
    alert(this);
};

var myObject = {
    foo: 'bar',
    toString: function () { return 'myObject'; }
};

myFunction();

var myProxyFunction = $.proxy(myFunction, myObject);
myProxyFunction();

다음은 배열을 순회하면서 원하는 값들로 구성된 배열을 생성하는 플러그인입니다. 7번 코드의 실행을 통해 arr 배열의 요소 객체의 id 속성만으로 구성된 배열을 생성해 반환합니다. 11번 코드는 새롭게 생성된 배열의 값을 확인하는 코드입니다.

var arr = [
    { id: 'a', tagName: 'li' },
    { id: 'b', tagName: 'li' },
    { id: 'c', tagName: 'li' }
];

var result = $.map(arr, function (value, index) {
    return value.id;
});

$.each(result, function (i, v) {
    alert(i + ' : ' + v);
});

다음은 특정 객체의 타입이 무엇인지를 확인하는 플러그인입니다.

alert($.isArray([])); // true
alert($.isFunction(function () { })); // true
alert($.isNumeric(3.14)); // true

alert($.type(true)); // boolean
alert($.type(3)); // number
alert($.type('test')); // string
alert($.type(function () { })); // function
alert($.type([])); // array
alert($.type(null)); // null
alert($.type(/test/)); // regexp
alert($.type(new Date())); date