레이블이 Java인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Java인 게시물을 표시합니다. 모든 게시물 표시

2017년 12월 23일 토요일

[STAN] Structure Analysis for Java > Tasks > Using the Structure Explorer

Using the Structure Explorer

Structure Explorer는 STAN의 주요 선택 도구이다. Structure Explorer는 인공물 관리 계층을 보여둔다. 인공물을 선택하면 그것이 현재 노드가 된다: 모든 다른 뷰들은 해당 노드에 대응되는 컨텐츠를 보여줌으로써 이를 반영한다.
explorer의 root node는 전체 project/application에 대응된다. root의 컨텍스트 메뉴는 Properties 아이템을 포함하는데 이는 application properties 다이얼로그를 열어준다(단축키는 ALT+ENTER).
만약 분석이 클래스를 제외하면, 이들은 root와 분리되어 "Filtered Classes"로 라벨링되어 보여진다.

Refresh 컨텍스트 메뉴 아이템을 사용하여(또는 explorer가 활성화된 상태에서 F5를 누른다) 분석을 재실행한다. 이는  밑에 포함된 리소스들이 디스크 상에서 변경되었다면 유용하다(클래스 파일들과 JAR들)

인공물들은 인공물 자체나 그것의 자식들중 하나가 특정 측정 기준으로 등급이 지정되는 경우 에러 마크를 보여준다. 경고 표시는 인공물이나 그것의 자식을 위한 최악의 등급이 주황색 범위에 빠지게 됨을 가리킨다. 결과적으로 에러나 경고가 없는 인공물들은 측정 기준을 위반하지 않고 있다는 것을 의미한다.

Excluding/Including Artifacts from the Structure Explorer

패키지 트리의 경우 평범한 패키지들과 클래스들은 Exclude 아이템 항목을 포함하는 컨텍스트 메뉴를 포함한다. Explorer로부터 인공물을 제외하는 것은 자동적으로 적절한 exclusion 패턴을 추가하고 분석을 재가동함으로써 어플리케이션 특성들을 변경할 것이다.

Note
Application properties를 열고 Filter tab으로 가서 현재 활성화된 패턴 리스트들을 손수 관리할 수 있다. 필터 패턴에 대한 더 많은 정보는 Specifying Class Filter Patterns를 참고해라.

필터링된 클래스들은 grayed-out icons으로 분리된 root 밑에 보여진다. 명확하게 제외된 패키지 트리들, 평범한 패키지들 그리고 클래스들은 In-out 마커로 장식되고 컨텍스트 메뉴의 Include로 다시 포한될 수 있다(부모가 제외되었을 때는 제외된다)

Warning
필터 패턴들은 어플리케이션 전체 영역이다. Thus, using the Exclude menu item while in Show Libraries mode may cause artifacts from other libraries be excluded as well (e.g. when excluding a package that extends over several libraries.

Linking the Structure Explorer with Views

synched Link with View button은 explorer와 뷰를 연결하는데 사용된다. 이 모드에서,
The synced Link with View button is used to link the explorer to views. In this mode,
  • Composition View에서 artifact를 탐색하는 것은 그 artifact를 현재 노드로 만들 것이다.
  • Couplings View에서 artifact를 탐색하는 것은 그 artifact를 현재 노드로 만들 것이다.

Structure Treemap

Structure Explorer가 활성화되었을 때(포커스를 가지고있는) OverView는 트리맵으로써 현재 노드 현재 노드에 뿌리를 둔 서브트리를 형상화해준다. 트리맵 셀을 더블 클릭하면 explorer에서 대응되는 노드가 선택되고 그것이 새로운 현재 노드가 된다.

  • 트리맵 셀의 색깔은 artifact 타입에 대응된다.(예를 들어, 클래스는 녹색, 인터페이스는 분홍색이다)
  • 트리맵 셀의 사이즈는 artifact에 포함된 코드의 양을 가리킨다.

[STAN] Structure Analysis for Java > Tasks > Analyzing Code > Setting Analysis Preferences

Setting Analysis Preferences

Analysis Preference 페이지는 Level of Detail과 Exclusion Patterns을 위한 기본값을 명세하게 해준다.(Specifying Class Filter Patterns을 보아라).
새로운 analysis를 설정할 때, preferences를 초기값으로 취하게 된다.

[STAN] STAN - Structure Analysis for Java > Tasks > Analyzing Code > Specifying Class Filter Patterns

Specifying Class Filter Patterns

Class filters는 분석을 형성하는 라이브러리들로부터 클래스의 부분집합들을 조정게 해준다. 두가지 종류의 필터가 있다.
  • Inclusions 특정 클래스들이 분석되게 하는 규칙을 명세하는 Ant-style 패턴들의 부분집합으로 주어질 수 있다. 만약 inclusions이 정의되지 않았다면 기본 패턴이 적용된
  • Exclusions 틀정 클래스들이 무시되도록 하는 규칙을 명세하는 Ant-style 패턴의 집합이 주어질 것이다.
만약 클래스가 적어도 하나의 inclusion 패턴에 매칭되고 어떤 exclusion 패턴에 매칭되지 않는다면 클래스는 분석의 부분이 된다.
패턴은 패스 구분자로 점'.' 대신에 슬래시'/'를 사용한다. 다음의 와일드카드들이 사용가능하다:

  1. ? 는 하나의 캐릭터와 매칭된다(드물게 사용된다)
  2. * 는 '/'를 포함하지 않는 연속된 캐릭터와 매칭된다.
  3. ** 는 어떤 캐릭터들과도 매칭된다.
패턴을 쉽게 사용하기 위해서는 몇몇 standard pattern 타입들과 일치시키자:

  1. "/*"으로 끝나고 어떤 와일드카드를 포함하지 않는다면 하나의 패키지와 매칭된다. 예를 들어 com/foo/bar/* 는 com.foo.bar 패키지의 모든 클래스들과 매칭된다.
  2. "/**"으로 끝나고 어떤 와일드카드를 포함하지 않는다면 패키지 트리와 매칭된다. 예를 들어, com/foo/bar/**는 com.foo.bar 패키지 트리로부터의 모든 클래스들과 매칭된다.  com.foo.bar.baz 등등.
  3. 어떤 와일드 카드도 없는 패턴은 하나의 클래스와 매칭된다(inner class를 포함하여). 예를 들어 com/foo/bar/Baz는 com.foo.bar.Baz와 com.foo.bar.Baz$1과 같은 중첩 클래스와 매칭된다.
위의 표준 타입의 패턴들은 만약 Structure Explorer로부터 인공적으로 제외되지 않는다면 자동으로 분석에 적용된다. 우리는 complex patters으로서 표준 타입과 매칭되지 않는 패턴들을 참조한다. complex patterns의 예는 다음과 같다.
Patterns of the above standard types are automatically applied to the analysis if you exclude artifacts from the Structure Explorer. We refer to patterns that do not match the standard types as complex patterns. Examples for complex patterns are:
  • **/test/** 는 "test" 세그먼트를 포함하는 패키지명의 모든 클래스들과 매칭된다. 
  • **/Test* 는 "Test"로 시작하는 모든 package 내의  클래스들과 매칭된다.
새로운 분석을 생성할 때, 기본 inclusion 패턴은 라이브러리와 기본 exclusion 패턴으로부터 모든 클래스들과 매칭한다.(이 패턴은 inclusion pattern 리스트에는 표시되지 않는다)

2017년 12월 22일 금요일

[STAN] Structure Analysis for Java > Tasks > Analyzing Code > Selecting Libraries

Selecting Libraries


Library Page는 분석의 코드 베이스를 형성하는 라이브러리의 리스트를 유지한다.

  • JAR 파일들을 추가하기 위해 Add JARs... 버튼을 누른다.
  • 클래스 폴더를 추가하기 위해 Add Foldr... 버튼을 누른다.
Up과 Down버튼은 라이브러리 아이템들의 순서를 정렬하기 위해 사용할 수 잇다. Structure Explorer은 Show Libraries 모드에서 이 순서대로 라이브러리들을 보여준다. 선택된 아이템을 제거하려면 Remove button을 사용한다.

[STAN] Structure Analysis for Java > Tasks > Analyzing Code > Choosing the Level of Detail

Choosing the Level of Detail

Level of Detail은 분석의 상세 정도를 결정한다.
  • Class - 분석의 상세 레벨은 클래스 계층으로 제한될 것이다. 필드나 메소드의 어떤 정보도 수집되지 않는다. 이 모드는 매우 큰 코드 베이스이거나 클래스의 상세 정보에는 관심이 없는 경우 시간과 메모리 사용을 감소시키기 위해 사용된다.
  • Member - 분석은 전체 레벨의 상세정보에 대해 수행된다. 필드와 메소드 정보가 수집된다. 메소드 매트릭스와 멤버 의존성 그래픽을 사용할 수 잇다.
새로운 분석을 생성할 때 상세정보의 기본 레벨은 Analysis Preferences로부터 취하게 된다.

[STAN]Structure Analysis for Java > Tasks > Analyzing Code

Analyzing Code

STAN의 RCP(stand-alone) 변종은 이른바 Projects라 불리는 것을 사용한다. Project settings은 workspace에 저장되어 수정될 수 있고 언저든지 실행할 수 있다.

Running an Analysis

Projects View는 workspace에 있는 모든 STAN 프로젝트들을 보여준다. 더블 클릭을 통해 프로젝트를 실행시키거나 컨텍스트 메뉴의 Analyze를 선택해서 실행시킬 수 있다.

Creating a new project

새로운 프로젝트를 열기 위해 메뉴바의 File > New 를 선택하거나 ALT+SHIFT+N을 선택한다. 다른 방법 : CTRL+N을 누르고 리스트에서 위저드를 선택한다.
프로젝트의 이름을 입력하고 아래에 설명하는데로 프로젝트 설정으로 통과하기 위해 다음을 누룬다.

Configuring an Analysis

Project Configuration 다이얼로그는 다음의 페이지를 갖고 있다.
  1. General - 이 페이지에서 Level of Detail을 선택할 수 있다.
  2. Libraries - 이 페이지는 코드베이스를 형성하는 라이브러리의 리스트를 유지한다.
  3. Filter - 이 페이지는 당신의 Class Filter Patterns을 설정할 수 있게 해준다.
다 설정했으면, Finish를 누른다.
존재하는 프로젝트의 설정을 변경하기 위해서는 Projects View의 컨텍스트 메뉴에서 Properties를 선택한다. 현재 분석중인 프로젝트를 위해서는 Structure Explorer에 있는 root의 컨텍스트 메뉴로부터 선택하면 된다.

2016년 8월 28일 일요일

[퍼온글]Inner class에서 local variable에 접근하려면 final이어야 하는 이유

안드로이드 개인 프로젝트를 진행하는 중에 옆에 있던 동기 누나가 생긴 오류로 코드를 들여다보았다.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);      
        fragmentManager=getFragmentManager();
        fragmentTransaction=fragmentManager.beginTransaction();
        ContentsViewFragment contentsViewFragment=new ContentsViewFragment();
        fragmentTransaction.add(R.id.fragment_container,contentsViewFragment);
        fragmentTransaction.commit();
        // 1. Action bar에서 navigation drawer toggle버튼을 클릭하면 navigation list가 나옴
        //    -> navigation list에 eventlistener 설정
        //    -> selectCategory()
        upperToolbar=(Toolbar)findViewById(R.id.upper_toolbar);
        setSupportActionBar(upperToolbar);
        // 2. 하단에 Action bar로 home, search, write, mypage 버튼 구성 및 eventㅣistener로 각 fragment로 연결
        //    -> selectMenu()
        //    -> home : ContentsViewFragment
        //    -> search: before search; BeforeSearchFragment, after search; ContentsViewFragment, action bar 검색어 입력 모드로 연결
        //    -> write: WriteCategoryFragment
        //    -> mypage: MyPageFragment
        //bottomToolbar는 standalone으로 구현
        bottomToolbar=(Toolbar)findViewById(R.id.bottom_toolbar);
        bottomToolbar.inflateMenu(R.menu.menu_bottom_bar);
        bottomToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener(){
@Override
public boolean onMenuItemClick(MenuItem item) {
        switch(item.getItemId()) {
        case R.id.home:
        ContentsViewFragment contentsViewFragment=new ContentsViewFragment();
        fragmentTransaction.replace(R.id.fragment_container,contentsViewFragment);
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
        break;
        case R.id.search:
        BeforeSearchFragment beforeSearchFragment=new BeforeSearchFragment();
        fragmentTransaction.replace(R.id.fragment_container,beforeSearchFragment);
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
        break;
        case R.id.write:
        WriteCategoryFragment writeCategoryFragment=new WriteCategoryFragment();
        fragmentTransaction.replace(R.id.fragment_container,writeCategoryFragment);
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
        break;
        case R.id.mypage:
        MyPageFragment myPageFragment=new MyPageFragment();
        fragmentTransaction.replace(R.id.fragment_container,myPageFragment);
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
        break;
        }
    return true;
  }
});
}
        });

 activity_main이 fragment로 화면을 바꾸어 주는데, 아래에 Toolbar로 변경할 수 있도록 구성했다. onMenuItemClick()에 switch문에서 id값에 따라 fragment를 바꿔준다. 코드를 보면 setOnMenuItemClickListener() 안에 new Toolbar.OnMenuItemClickListener() 로 Anonymous class가 선언되고 그 클래스의 onMenuItemClick() method 내에서 switch 구문을 구현한 것이다. 

코드를 실행하니 Inner class에서 local variable에 선언 된 변수에 접근하려니 에러가 발생했는데 그 내용이 'Inner class가 local variable에 접근하고 있다. 해결하려면 local variable을 final로 선언해야 한다' 라는 내용이었다.
 onMenuItemClick()의 switch 구문에서 onCreate()에서 선언된 contentsViewFragment 변수에 접근하면서 생긴 오류였다.

그 이유가 무엇일까 찾아보다가 깊이 있는 분석이 필요함을 느꼈다.

먼저 Inner Class의 개념에 대해 정확히 파악할 필요가 있었다. Java에는 Nested Class 가 있는데, 이 안에 Inner Class와 Lamda Expression이 포함된다. Inner Class는 다시 Local Class와 Anonymous Class가 있다. Java에서는 왜 Nested Class가 필요해졌으며, Inner Class에는 Local Class와 Anonymous Class가 분류되었을까? 이것에 대한 이해가 없이는 그 아래에 대한 이해가 힘들 것 같았다.

Nested Class가 왜 등장하게 되었는지 살펴보니
1. It is a way of logically grouping classes that are only used in one place
 개념적으로 하나의 클래스 B가 오직 다른 클래스 A에서만 유용하다면, B 클래스는 A 클래스 안에서 사용하는 것이 좋다는 것이다. 굳이 다른 곳에서 쓰는 일이 없는데 클래스로 빼낼 필요가 있을까라는 말인 듯 하다. 클래스로 만든 다는 것은 재사용성을 높이기 위함이 있으니까..

2. It increases encapsulation
 B 클래스가 A 클래스의 멤버에 접근해야 한다. 그러려면 public으로 선언하거나 protected로 선언해서 상속을 받아야 할 것이다. 하지만 inner class로 선언해두면 private으로 선언할 수 있다. 그리고 B class는 안에 있기 때문에 외부(outside world)로부터 숨을 수 있다.

3. It can lead to more readable and maintainable code
 좀 더 가독성이 좋고 유지보수하기 쉬운 코드가 된다고 한다. 

Nested Class는 2개의 카테고리로 나뉘는데 static nested class와 non-static nested class(inner class)로 나뉜다. Inner class는 enclosing class의 멤버가 private이더라도 접근할 수 있다.



Inner class의 경우 추가적으로 2가지 타입이 더 있다. Inner class는 method 안에서 선언할 수도 있는데, method 안에 선언하면 local class라고 부르고, class name 없이 method body 안에 선언하면 anonymous class라고 부른다.

Local class는 enclosing class의 멤버에 접근할 수 있다. method 내에 선언하는 class를 local class라고 하니 정확히는 method 내에 선언 된 변수를 의미하는 듯 하다. 그런데 Local class는 오직 final로 선언된 local variable에만 접근할 수 있다. 
"When a local class accesses a local variable or parameter of the enclosing block, it captures that variable or parameter."

Local Class가 local variable 또는 parameter에 접근(Java 8부터는 parameter에도 접근할 수 있다)하려고 하면 그 변수를 captured 한다는데 정확히 무슨 뜻인지 모르겠다. 복사한다는 뜻일까?

Anonymous Class도 Local Class와 마찬가지로 enclosing class의 member에 접근을 하려면 final로 선언이 되 있어야 한다고 했다.




이제 JVM 내부에서 어떻게 동작이 되길래 final에 접근하는지에 대한 고민이 필요했다.

http://www.slipp.net/questions/278 에서도 같은 고민의 글이 있어서 참고를 했다.

위에 읽은 글과 블로그의 내용을 바탕으로 이해한 것은 Anonymous Class나 Local Class에서 local variable에 접근을 하면 그 변수 값을 복사(captured)해서 사용하기 때문에 2개의 변수가 생겨서 값이 불일치 하는 상황이 생길 수 있다. 따라서 final로 선언해서 그런 일을 방지하려고 하는 것이다.
 위의 블로그에는 thread safe에 관해서도 얘기를 하고 있는데 거기까지는 이해가 되지 않고 있다. 좀 더 자세히 생각해봐야 할 것 같다.

[출처]http://ybin.tistory.com/8