Các tính năng ẩn của Java


295

Sau khi đọc các tính năng ẩn của C #, tôi tự hỏi, một số tính năng ẩn của Java là gì?


17
Lưu ý rằng không phải lúc nào cũng là một ý tưởng tuyệt vời để sử dụng các tính năng ẩn này; đôi khi họ ngạc nhiên và bối rối cho người khác đọc mã của bạn.
Kevin Bourrillion

1
Bạn (/ ai đó) nên tổng hợp các câu trả lời gọn gàng trong phần câu hỏi như câu hỏi C #.
ripper234

Câu trả lời:


432

Double Brace Khởi tạo làm tôi ngạc nhiên một vài tháng trước khi tôi lần đầu tiên phát hiện ra nó, chưa bao giờ nghe về nó trước đây.

ThreadLocals thường không được biết đến rộng rãi như là một cách để lưu trữ trạng thái trên mỗi luồng.

Do JDK 1.5 Java đã có các công cụ đồng thời mạnh mẽ và được triển khai rất tốt ngoài các khóa, chúng sống trong java.util.concản và một ví dụ thú vị đặc biệt là gói con java.util.concản.atomic có chứa các nguyên hàm an toàn luồng thực hiện so sánh -và hoạt động hoán đổi và có thể ánh xạ tới các phiên bản hỗ trợ phần cứng thực tế của các hoạt động này.


40
Mặc dù khởi tạo cú đúp ... kỳ lạ ... Tôi sẽ cảnh giác khi áp dụng thành ngữ cụ thể đó quá rộng rãi, vì nó thực sự tạo ra một lớp con ẩn danh của đối tượng, có thể gây ra các vấn đề về mã / băm khó hiểu. java.util.conc hiện là một gói thực sự tuyệt vời.
MB.

6
Tôi đã dạy Java và đây là lần đầu tiên tôi bắt gặp cú pháp này ... điều này cho thấy bạn không bao giờ ngừng học hỏi = 8-)
Yuval

49
Lưu ý rằng nếu bạn giữ lại một tham chiếu đến một bộ sưu tập được khởi tạo với thành ngữ "cú đúp kép" này (hoặc nếu chúng ta gọi nó bằng tên thật của nó - lớp đồng nghĩa với khối khởi tạo), bạn sẽ giữ một tham chiếu đến đối tượng bên ngoài có thể gây ra bộ nhớ khó chịu rò rỉ. Tôi khuyên bạn nên tránh nó hoàn toàn.
ddimitrov

51
"Khởi tạo cú đúp" là một cái tên rất uyển chuyển để tạo ra một lớp bên trong ẩn danh, che đậy những gì đang thực sự xảy ra và làm cho nó nghe như thể các lớp bên trong được sử dụng theo cách này. Đây là một mẫu tôi thích vẫn bị ẩn.
erickson

11
Hầu như, nó không thực sự là một khối tĩnh mà là "khối khởi tạo" khác với vì nó được thực thi vào một thời điểm khác (xem liên kết tôi đưa vào câu trả lời để biết thêm chi tiết)
Boris Terzic

279

Liên minh chung trong phương sai tham số loại:

public class Baz<T extends Foo & Bar> {}

Ví dụ: nếu bạn muốn lấy một tham số cả So sánh và Bộ sưu tập:

public static <A, B extends Collection<A> & Comparable<B>>
boolean foo(B b1, B b2, A a) {
   return (b1.compareTo(b2) == 0) || b1.contains(a) || b2.contains(a);
}

Phương thức giả định này trả về true nếu hai tập hợp đã cho bằng nhau hoặc nếu một trong hai tập hợp đó chứa phần tử đã cho, ngược lại là false. Điểm cần chú ý là bạn có thể gọi các phương thức của cả So sánh và Thu thập trên các đối số b1 và b2.


Sử dụng yêu thích của tôi cho việc này là khi bạn cần một phương pháp chấp nhận Kết quả có thể bổ sung.
Neil Coffey

5
Có thể có "HOẶC" ở đó thay vì &?
chuỗi chính

9
@Grasper: Không, HOẶC (tách rời liên minh) không được cung cấp trong bối cảnh đó. Nhưng bạn có thể sử dụng một kiểu dữ liệu hợp nhất rời rạc như Either <A, B>. Loại này là kép của loại Ghép <A, B>. Nhìn vào thư viện Java Chức năng hoặc các thư viện lõi Scala để biết ví dụ về kiểu dữ liệu đó.
Apocalisp

5
Bạn nên nói rằng bạn PHẢI chỉ mở rộng một lớp và một số giao diện -> lớp công khai Baz <T mở rộng Clazz & Interface1 & InterfaceI ... và không phải lớp Baz <T kéo dài Clazz1 & ClazzI>
JohnJohnGa

220

Tôi đã ngạc nhiên bởi các trình khởi tạo cá thể vào ngày khác. Tôi đã xóa một số phương thức gấp mã và cuối cùng tạo ra nhiều bộ khởi tạo cá thể:

public class App {
    public App(String name) { System.out.println(name + "'s constructor called"); }

    static { System.out.println("static initializer called"); }

    { System.out.println("instance initializer called"); }

    static { System.out.println("static initializer2 called"); }

    { System.out.println("instance initializer2 called"); }

    public static void main( String[] args ) {
        new App("one");
        new App("two");
  }
}

Thực hiện mainphương thức sẽ hiển thị:

static initializer called
static initializer2 called
instance initializer called
instance initializer2 called
one's constructor called
instance initializer called
instance initializer2 called
two's constructor called

Tôi đoán những thứ này sẽ hữu ích nếu bạn có nhiều hàm tạo và cần mã chung

Họ cũng cung cấp đường cú pháp để khởi tạo các lớp học của bạn:

List<Integer> numbers = new ArrayList<Integer>(){{ add(1); add(2); }};

Map<String,String> codes = new HashMap<String,String>(){{ 
  put("1","one"); 
  put("2","two");
}};

38
Ưu điểm của phương thức này so với một phương thức rõ ràng cần được gọi là nếu ai đó thêm một hàm tạo sau này, họ không cần phải nhớ gọi init (); Điều đó sẽ được thực hiện tự động. Điều này có thể ngăn ngừa lỗi của các lập trình viên trong tương lai.
Ông Sáng bóng và Mới 安

40
Ngoài ra, không giống như một phương thức init (), nó có thể khởi tạo các trường cuối cùng.
Darron

2
Điều gì nếu bạn mở rộng lớp học và khởi tạo những đứa trẻ khác nhau? Nó vẫn sẽ hành xử theo cách tương tự?
Kezzer

12
Mọi người thường không chấp nhận các chứng chỉ (ví dụ stackoverflow.com/questions/281100/281127#281127 ) và đặc biệt đặt câu hỏi về giá trị kỹ thuật của họ. Nhưng nếu nhiều lập trình viên ở đây đã nghiên cứu về SCJP của họ, thì đây sẽ không được coi là một "tính năng ẩn". ;-)
Jonik

12
Tôi đặt cược ngay cả cuốn sách "java trong 24 giờ" có "tính năng rõ ràng" này. đọc thêm mọi người :) (
Özgür

201

JDK 1.6_07 + chứa một ứng dụng có tên VisualVM (bin / jvisualvm.exe) là một GUI đẹp trên nhiều công cụ. Nó có vẻ toàn diện hơn JConsole.


Và nó có một plugin (nó là một netbeans thingie) cho phép nó sử dụng các plugin Jconsole. Khá đẹp.
Thorbjørn Ravn Andersen

VisualVM là điều tốt nhất kể từ khi bánh mì cắt lát, thực sự! Quá tệ, nó không có tất cả các tính năng khi chạy với JDK 1.5
sandos

Tôi thấy VisualVM chậm hoặc không sử dụng được trong một số trường hợp. YourKit thương mại không có vấn đề này, nhưng rất tiếc là không miễn phí.
Roalt

Các phiên bản gần đây hơn của Visual VM, từ JDK 1.6.0_22 trở lên, được cải tiến hơn nhiều. Tôi cá là JDK1.7 có phiên bản thậm chí còn tốt hơn.
djangofan


156

Đối với hầu hết mọi người, tôi phỏng vấn cho các vị trí nhà phát triển Java được dán nhãn là rất đáng ngạc nhiên. Đây là một ví dụ:

// code goes here

getmeout:{
    for (int i = 0; i < N; ++i) {
        for (int j = i; j < N; ++j) {
            for (int k = j; k < N; ++k) {
                //do something here
                break getmeout;
            }
        }
    }
}

Ai nói gototrong java chỉ là một từ khóa? :)


2
Chà, tôi thích có một lựa chọn để làm điều đó theo nhiều cách. Ví dụ, tôi thấy mọi người sử dụng System.exit (1); trong mã Servlet và EJB, nhưng điều đó không có nghĩa là chúng ta nên loại bỏ System.exit (); từ JDK, phải không?
Georgy Bolyuba

31
Trong một số trường hợp, trong cấu trúc vòng lặp lồng nhau, có thể hữu ích để tiếp tục lặp lại tiếp theo của vòng lặp bên ngoài. Đây sẽ là một sử dụng hợp lý của tính năng này.
alasdairg

75
Điều đặc biệt xa lạ với nhiều lập trình viên (và có lẽ cũng như vậy) là bạn thực sự có thể gắn nhãn và thoát ra khỏi BẤT K block khối cũ nào. Nó không phải là một vòng lặp-- bạn chỉ cần xác định một số khối tùy ý, đặt nhãn và sử dụng dấu ngắt với nó.
Neil Coffey

27
Nó hoàn toàn không phải là một goto, nó chỉ có thể quay lại lần lặp trước (nghĩa là: bạn không thể nhảy về phía trước). Đây là cơ chế tương tự xảy ra khi một lần lặp trả về sai. Nói java có goto giống như nói bất kỳ ngôn ngữ nào có trình biên dịch tạo ra lệnh JUMP có câu lệnh goto.
Thây ma

4
Vì vậy, bạn phỏng vấn dựa trên những câu đố về Java hơn là khả năng giải quyết vấn đề và suy nghĩ thông qua các thiết kế. Tôi chắc chắn rằng tôi sẽ không bao giờ phỏng vấn với công ty của bạn. :)
Javid Jamae

144

Làm thế nào về các kiểu trả về covariant đã có tại JDK 1.5? Nó được công bố khá kém, vì nó là một bổ sung unsexy, nhưng theo tôi hiểu, nó hoàn toàn cần thiết cho thuốc generic hoạt động.

Về cơ bản, trình biên dịch bây giờ cho phép một lớp con thu hẹp kiểu trả về của một phương thức được ghi đè thành một lớp con của kiểu trả về của phương thức ban đầu. Vì vậy, điều này được cho phép:

class Souper {
    Collection<String> values() {
        ...
    }
}

class ThreadSafeSortedSub extends Souper {
    @Override
    ConcurrentSkipListSet<String> values() {
        ...
    }
}

Bạn có thể gọi của lớp con valuesphương pháp và có được một sợi an toàn sắp xếp Setcủa Strings mà không cần phải cast xuống đến ConcurrentSkipListSet.


Bạn có thể cung cấp một ví dụ sử dụng?
Allain Lalonde

24
Tôi sử dụng nó rất nhiều. clone () là một ví dụ tuyệt vời. Nó được cho là trả về Object, có nghĩa là bạn phải nói ví dụ (List) list.clone (). Tuy nhiên nếu bạn khai báo là List clone () {...}, thì việc chọn diễn viên là không cần thiết.
Jason Cohen

142

Chuyển quyền kiểm soát trong một khối cuối cùng ném đi bất kỳ ngoại lệ. Đoạn mã sau không ném RuntimeException - nó bị mất.

public static void doSomething() {
    try {
      //Normally you would have code that doesn't explicitly appear 
      //to throw exceptions so it would be harder to see the problem.
      throw new RuntimeException();
    } finally {
      return;
    }
  }

Từ http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html


7
Điều đó thật khó chịu, nhưng đó cũng chỉ là một hậu quả hợp lý của cách thức hoạt động cuối cùng. Kiểm soát luồng thử / bắt / cuối cùng thực hiện những gì nó dự định làm, nhưng chỉ trong một số giới hạn nhất định. Tương tự, bạn phải cẩn thận để không gây ra ngoại lệ trong khối bắt / cuối cùng, hoặc bạn cũng sẽ vứt bỏ ngoại lệ ban đầu. Và nếu bạn thực hiện System.exit () trong khối thử, khối cuối cùng sẽ không được gọi. Nếu bạn phá vỡ dòng chảy bình thường, bạn sẽ phá vỡ dòng chảy bình thường ...
Neil Coffey

Đừng sử dụng cuối cùng {return; } nhưng cuối cùng chỉ là {code mà không trả về}. Điều này là hợp lý, vì cuối cùng cũng có ý định được thực hiện khi có ngoại lệ xảy ra và ý nghĩa duy nhất có thể có của việc trả về là trình xử lý ngoại lệ phải bỏ qua ngoại lệ và - thực sự - trả về.
extraneon

21
Điều này có vẻ giống như một "gotcha" hơn là một tính năng ẩn, mặc dù có nhiều cách nó có thể được sử dụng như một, sử dụng phương pháp này sẽ không phải là một ý tưởng hay.
davenpcj

Eclipse phát ra một cảnh báo nếu bạn làm điều này. Tôi đang ở với Eclipse. Nếu bạn muốn bắt một ngoại lệ ... thì hãy bắt một ngoại lệ.
helios

Đó là những gì bạn phải trả cho mã bẩn trả về từ giữa phương thức. Nhưng vẫn là một ví dụ tốt đẹp.
Rostislav Matl

141

Không thấy ai đề cập đến trường hợp được thực hiện theo cách mà việc kiểm tra null là không cần thiết.

Thay vì:

if( null != aObject && aObject instanceof String )
{
    ...
}

chỉ dùng:

if( aObject instanceof String )
{
    ...
}

9
Thật xấu hổ vì đây là một tính năng ít được biết đến. Tôi đã thấy rất nhiều mã tương tự như khối mã đầu tiên.
Peter Dolberg

4
Đó là bởi vì Java có một loại null đặc biệt (ẩn) mà bạn không nhìn thấy, cũng không thể tham khảo.
Nick Hristov

Điều tồi tệ hơn là kiểm tra null trước khi freeing hoặc deleteing trong C / C ++. Như một khái niệm cơ bản.
Thomas Eding

134

Cho phép các phương thức và các nhà xây dựng trong enums làm tôi ngạc nhiên. Ví dụ:

enum Cats {
  FELIX(2), SHEEBA(3), RUFUS(7);

  private int mAge;
  Cats(int age) {
    mAge = age;
  }
  public int getAge() {
    return mAge;
   }
}

Bạn thậm chí có thể có một "thân lớp cụ thể không đổi" cho phép một giá trị enum cụ thể để ghi đè các phương thức.

Thêm tài liệu ở đây .


20
Tính năng thực sự tuyệt vời thực sự - làm cho OO enum và giải quyết rất nhiều vấn đề khởi tạo một cách rất sạch sẽ.
Bill K

5
Enum là người độc thân? Enum chỉ có một giá trị?
Georgy Bolyuba

6
Georgy: Singleton là một ví dụ của đối tượng, không phải là một đối tượng có một giá trị.
dshaw

20
@Georgy: xem thêm Mục 3 trong Java hiệu quả của Joshua Bloch (tái bản lần 2); "Trong khi phương pháp này vẫn chưa được áp dụng rộng rãi, một loại enum đơn yếu tố là cách tốt nhất để thực hiện một singleton."
Jonik

3
Tiểu nitlog: mAgenên là cuối cùng. Hiếm khi có một lý do cho các feld không cuối cùng trong enums.
Joachim Sauer

121

Các tham số loại cho các phương thức chung có thể được chỉ định rõ ràng như vậy:

Collections.<String,Integer>emptyMap()

10
Và bởi chúa là nó xấu xí và khó hiểu. Và không liên quan đến loại an toàn.
Chris Broadfoot

8
Tôi thích điều này. Nó làm cho mã của bạn rõ ràng hơn một chút và như vậy rõ ràng hơn đối với người nghèo, người sẽ phải duy trì nó trong một hoặc hai năm.
extraneon

6
Điều này thực sự rất hữu ích trong các tình huống mà bạn đã khai báo một phương thức chung tĩnh như public static <T> T foo(T t). Sau đó, bạn có thể thực hiện cuộc gọi đếnClass.<Type>foo(t);
Finbarr

Vì một số lý do, điều này dường như không hoạt động với các phương thức nhập tĩnh .. Tôi tự hỏi tại sao.
oksayt

Điều này đặc biệt hữu ích khi sử dụng ifs ternary với lợi nhuận. Ví dụ return set1.equals(set2) ? new ArrayList<String>(set1) : Collections.<String>emptyList(). Nó cũng hữu ích cho một số lời gọi phương thức trong đó một Collections.emptyMap () đơn giản sẽ đưa ra một lỗi biên dịch.
Andreas Holstenson

112

Bạn có thể sử dụng enums để thực hiện một giao diện.

public interface Room {
   public Room north();
   public Room south();
   public Room east();
   public Room west();
}

public enum Rooms implements Room {
   FIRST {
      public Room north() {
         return SECOND;
      }
   },
   SECOND {
      public Room south() {
         return FIRST;
      }
   }

   public Room north() { return null; }
   public Room south() { return null; }
   public Room east() { return null; }
   public Room west() { return null; }
}

EDIT: Nhiều năm sau ....

Tôi sử dụng tính năng này ở đây

public enum AffinityStrategies implements AffinityStrategy {

https://github.com/peter-lawrey/Java-Thread-Affinity/blob/master/src/main/java/vanilla/java/affinity/AffinityStrargeties.java

Bằng cách sử dụng một giao diện, các nhà phát triển có thể xác định chiến lược của riêng họ. Sử dụng một enumphương tiện tôi có thể định nghĩa một bộ sưu tập (gồm năm) được xây dựng trong những bộ.


27
Đây là sự điên rồ. (+1)
Cephalepad

12
@Arian đây không phải là điên rồ. ĐIỀU NÀY. LÀ. JAVAAAAAAHHHH!
slezica

1
WHAAAAAT không, tôi với Adrian. Đây không phải là Java. Đây là sự điên rồ. Tôi sắp chết để sử dụng cái này.
slezica

104

Kể từ Java 1.5, Java hiện có một cú pháp rõ ràng hơn để viết các hàm của arity biến. Vì vậy, thay vì chỉ truyền một mảng, bây giờ bạn có thể làm như sau

public void foo(String... bars) {
   for (String bar: bars)
      System.out.println(bar);
}

các thanh được tự động chuyển thành mảng của loại được chỉ định. Không phải là một chiến thắng lớn, nhưng dù sao cũng là một chiến thắng.


23
Điều quan trọng về vấn đề này là khi gọi phương thức, bạn có thể viết: foo ("thứ nhất", "thứ hai", "thứ ba")
Steve Armstrong

9
vì vậy thế giới xin chào cũ có thể được viết lại; public static void main (String ... args) {System.out.println ("Hello World!"); }
Karussell

@Karussell Có thể, nhưng có vẻ như các cuộc tranh luận không liên quan: p
Kelly Elton

93

Yêu thích của tôi: đổ tất cả dấu vết ngăn xếp chủ đề để tiêu chuẩn ra.

cửa sổ: CTRL- Breaktrong cửa sổ java cmd / console của bạn

unix: kill -3 PID


15
Ngoài ra ctrl- \ trong Unix. Hoặc sử dụng jstack từ JDK.
Tom Hawtin - tackline

9
Cảm ơn, bạn vừa dạy tôi bàn phím của tôi có một Breakphím.
Amy B

2
Trên các cửa sổ, CTRL-BREAK chỉ hoạt động nếu bạn có quá trình đang chạy trong cửa sổ bảng điều khiển hiện tại. Bạn có thể sử dụng JAVA_HOME / bin / jstack.exe thay thế. Chỉ cần cung cấp cho nó với id tiến trình Windows.
Javid Jamae

Tôi nghĩ rằng nó đã bị giết -SIGQUIT
Nick Hristov

@Nick, có SIGQUIT thường là tín hiệu # 3.
Chris Mazzola

89

Một vài người đã đăng bài về khởi tạo cá thể, đây là một cách sử dụng tốt cho nó:

Map map = new HashMap() {{
    put("a key", "a value");
    put("another key", "another value");
}};

Là một cách nhanh chóng để khởi tạo bản đồ nếu bạn chỉ cần làm một việc gì đó nhanh chóng và đơn giản.

Hoặc sử dụng nó để tạo một nguyên mẫu khung đu nhanh:

JFrame frame = new JFrame();

JPanel panel = new JPanel(); 

panel.add( new JLabel("Hey there"){{ 
    setBackground(Color.black);
    setForeground( Color.white);
}});

panel.add( new JButton("Ok"){{
    addActionListener( new ActionListener(){
        public void actionPerformed( ActionEvent ae ){
            System.out.println("Button pushed");
        }
     });
 }});


 frame.add( panel );

Tất nhiên nó có thể bị lạm dụng:

    JFrame frame = new JFrame(){{
         add( new JPanel(){{
               add( new JLabel("Hey there"){{ 
                    setBackground(Color.black);
                    setForeground( Color.white);
                }});

                add( new JButton("Ok"){{
                    addActionListener( new ActionListener(){
                        public void actionPerformed( ActionEvent ae ){
                            System.out.println("Button pushed");
                        }
                     });
                 }});
        }});
    }};

Bằng cách nào đó, có một chút như thể từ khóa "với" (chức năng, thực sự) đã được thêm vào Java. Có thể rất tiện dụng, gần đây tôi làu bàu vì init của mảng không có sẵn cho Bộ sưu tập. Cảm ơn!
PhiLho

15
Có một tác dụng phụ của việc sử dụng này, mặc dù. Các đối tượng ẩn danh được tạo, có thể không luôn luôn tốt.
amit

17
Mặc dù sau khi nhìn vào nó nhiều hơn, tôi phải nói rằng tôi bị thu hút một cách kỳ lạ vào việc làm tổ tự nhiên mà nó cung cấp, ngay cả phiên bản "Lạm dụng".
Bill K

4
Đúng - Tôi khá thích phiên bản 'bị lạm dụng', tôi nghĩ điều đó thực sự rất rõ ràng và dễ đọc, nhưng có lẽ đó chỉ là tôi.
barryred

3
Hoàn toàn đồng ý, hệ thống phân cấp của mã phản ánh thứ bậc của gui là một cải tiến rất lớn đối với một chuỗi các cuộc gọi phương thức.
opsb

88

Proxy động (được thêm vào trong 1.3) cho phép bạn xác định loại mới trong thời gian chạy phù hợp với giao diện. Nó có ích một số lần đáng ngạc nhiên.


10
Proxy động là một lý do tuyệt vời để chọn viết giao diện Foo và sử dụng giao diện đó ở mọi nơi, với lớp "FooImpl" mặc định. Ban đầu nó có vẻ xấu ("Tại sao không chỉ có một lớp gọi là Foo?") Nhưng những lợi ích về tính linh hoạt trong tương lai và khả năng giả cho các bài kiểm tra đơn vị là tiện dụng. Mặc dù có nhiều cách để làm điều đó cho các giao diện không, nhưng chúng thường yêu cầu các công cụ bổ sung như cblib.
Darien

82

khởi tạo cuối cùng có thể được hoãn lại.

Nó đảm bảo rằng ngay cả với một luồng giá trị trả về logic phức tạp luôn được đặt. Thật quá dễ dàng để bỏ lỡ một trường hợp và vô tình trở về null. Nó không làm cho việc trả về null là không thể, chỉ rõ ràng là nó có chủ đích:

public Object getElementAt(int index) {
    final Object element;
    if (index == 0) {
         element = "Result 1";
    } else if (index == 1) {
         element = "Result 2";
    } else {
         element = "Result 3";
    }
    return element;
}

Thật bất ngờ. Người ta có thể nói một cách công bằng, "Giá trị của biến cuối cùng có thể được đặt một lần", bất kể tập hợp xảy ra ở đâu?
David Koelle

29
Có, nhưng mạnh mẽ hơn: "Giá trị của biến cuối cùng phải được đặt một lần"
Allain Lalonde

6
+1 Đồng ý, đây là một công cụ có giá trị khác để phát hiện lỗi tại thời điểm biên dịch và một công cụ mà các lập trình viên có vẻ ngại sử dụng vì một số lý do. Lưu ý rằng vì từ Java 5 trở đi, 'Final' cũng có ý nghĩa về an toàn luồng, nên việc có thể đặt biến cuối cùng trong hàm tạo là vô giá.
Neil Coffey

4
Mặc dù đối với phương pháp cụ thể này, tôi chỉ sử dụng nhiều lợi nhuận. Trong thực tế, trong hầu hết các trường hợp áp dụng điều này, có lẽ tôi sẽ cấu trúc lại nó thành một phương thức riêng biệt và sử dụng nhiều lợi nhuận.
ripper234

Tôi thích điều này! Tôi luôn xóa từ khóa cuối cùng vì tôi nghĩ nó sẽ thất bại. cảm ơn!
KARASZI István

62

Tôi nghĩ một tính năng "bị bỏ qua" khác của java là chính JVM. Nó có lẽ là VM tốt nhất hiện có. Và nó hỗ trợ rất nhiều ngôn ngữ thú vị và hữu ích (Jython, JRuby, Scala, Groovy). Tất cả những ngôn ngữ có thể dễ dàng và liền mạch hợp tác.

Nếu bạn thiết kế một ngôn ngữ mới (như trong trường hợp scala), ngay lập tức bạn có sẵn tất cả các thư viện hiện có và ngôn ngữ của bạn là "hữu ích" ngay từ đầu.

Tất cả các ngôn ngữ đó sử dụng tối ưu hóa HotSpot. VM rất tốt theo dõi và gỡ lỗi.


18
Không. Nó thực sự không phải là một VM tốt. Nó chỉ được thiết kế để chạy JAVA. Ngôn ngữ động và chức năng không chữ không hoạt động tốt với nó. Trong số bạn muốn sử dụng VM, bạn nên sử dụng .NET / Mono. Nó được thiết kế để hoạt động với MỌI ngôn ngữ ...
Hades32

14
Trên thực tế, JVM chỉ được thiết kế để chạy Mã byte Java. Bạn có thể biên dịch các ngôn ngữ hiện đại nhất sang Mã byte Java. Về những điều duy nhất mà Java Bytecode thiếu là hỗ trợ ngôn ngữ động, con trỏ và hỗ trợ đệ quy đuôi.
mcjabberz

12
@ Hades32: thực ra .NET VM khá giống với JVM. Nó chỉ nhận được hỗ trợ cho các ngôn ngữ động tương đối gần đây (với DLR) và Java 7 cũng sắp có được sự hỗ trợ đó. Và "MỌI ngôn ngữ" cổ điển của .NET (C #, Visual Basic.NET, ...) đều có khá nhiều chính xác cùng một bộ tính năng.
Joachim Sauer

13
JVM không hỗ trợ chung chung, trong khi .NET VM thì có. JVM không ở đâu gần nhất.
Bịt mắt

3
Không giảm giá các khiếu nại về các tính năng ngôn ngữ cụ thể không được JVM hỗ trợ trực tiếp ... nhưng tôi có xu hướng nghĩ rằng tính ổn định, tính nhất quán đa nền tảng và hiệu suất tốt là rất xa so với lý do JVM được thêm điểm. Tôi đã làm việc với Java phía máy chủ trong nhiều năm nay trên nhiều nền tảng (bao gồm AS / 400) và đã có thể quên đi hoàn toàn về nó - các lỗi luôn có rất nhiều trong mã mà tôi có thể sửa và nó chỉ đơn giản là không sụp đổ.
Rob Whelan

58

Bạn có thể định nghĩa một lớp con ẩn danh và gọi trực tiếp một phương thức trên nó ngay cả khi nó không thực hiện giao diện.

new Object() {
  void foo(String s) {
    System.out.println(s);
  }
}.foo("Hello");

@Vuntic - Nó cho phép bạn xác định một lớp đơn giản trong bối cảnh cần thiết.
ChaosPandion

1
@ Sự hỗn loạn, nhưng tại sao? Có một ví dụ thực tế nơi nó hữu ích?
Thorbjørn Ravn Andersen

10
@Wouter - Trong trường hợp đó, phương thức được gọi trên đối tượng ẩn danh ( start()) không thực sự được xác định trong lớp con ...
Axel

Trên thực tế, đây là một tính năng rất hữu ích nếu bạn mở rộng một lớp cơ sở thực hiện một số thiết lập cần thiết, gọi phương thức bạn viết và sau đó thực hiện phân tách. Loại bỏ điều đó bằng cách gọi một phương thức trong lớp cơ sở (mà tôi có lẽ sẽ không đặt cùng tên). Có một ví dụ sử dụng (không định nghĩa) ở đây
AmigoNico

56

Các asList phương pháp trong java.util.Arrayscho phép một sự kết hợp tốt đẹp của varargs, phương pháp chung chung và autoboxing:

List<Integer> ints = Arrays.asList(1,2,3);

15
bạn muốn bọc danh sách được trả về bằng hàm tạo Danh sách nếu không int sẽ có kích thước cố định (vì nó được hỗ trợ bởi mảng)
KitsuneYMG

2
Arrays.asListtính năng bất thường mà bạn có thể set()yếu tố nhưng không add()hoặc remove(). Vì vậy, tôi thường bọc nó trong một new ArrayList(...)hoặc trong một Collections.unmodifiableList(...), tùy thuộc vào việc tôi muốn danh sách có thể sửa đổi hay không.
Christian Semrau

53

Sử dụng từ khóa này để truy cập các trường / phương thức chứa lớp từ một lớp bên trong. Trong ví dụ bên dưới, khá giả định, chúng tôi muốn sử dụng trường sắp xếp tăng dần của lớp container từ lớp bên trong ẩn danh. Sử dụng ContainerClass.this.sortAsceinating thay vì this.sortAsceinating thực hiện thủ thuật.

import java.util.Comparator;

public class ContainerClass {
boolean sortAscending;
public Comparator createComparator(final boolean sortAscending){
    Comparator comparator = new Comparator<Integer>() {

        public int compare(Integer o1, Integer o2) {
            if (sortAscending || ContainerClass.this.sortAscending) {
                return o1 - o2;
            } else {
                return o2 - o1;
            }
        }

    };
    return comparator;
}
}

4
Điều đó chỉ cần thiết nếu bạn đã bỏ qua tên (trong trường hợp của bạn, với tên tham số phương thức). Nếu bạn đã gọi đối số một cái gì đó khác, thì bạn có thể truy cập trực tiếp vào biến thành viên sắp xếp của lớp Container mà không cần sử dụng 'this'.
sk.

7
Nó vẫn hữu ích để có một tham chiếu đến lớp kèm theo, ví dụ. nếu bạn cần truyền nó cho một số phương thức hoặc construtor.
PhiLho

Thường được sử dụng trong phát triển bố cục Android, để lấy Ngữ cảnh từ, giả sử, người nghe của một nút, với MyActivity.this.
Espinchi

52

Không thực sự là một tính năng, nhưng một mẹo thú vị mà tôi đã phát hiện gần đây trong một số trang Web:

class Example
{
  public static void main(String[] args)
  {
    System.out.println("Hello World!");
    http://Phi.Lho.free.fr

    System.exit(0);
  }
}

là một chương trình Java hợp lệ (mặc dù nó tạo ra một cảnh báo). Nếu bạn không thấy lý do tại sao, hãy xem câu trả lời của Gregory! ;-) Vâng, cú pháp tô sáng ở đây cũng cho một gợi ý!


15
gọn gàng, một nhãn hiệu với một bình luận :)
Thorbjørn Ravn Andersen

46

Đây không phải là "tính năng ẩn" chính xác và không hữu ích lắm, nhưng có thể cực kỳ thú vị trong một số trường hợp:
Class sun.misc.Unsafe - sẽ cho phép bạn thực hiện quản lý bộ nhớ trực tiếp trong Java (thậm chí bạn có thể viết mã Java tự sửa đổi bằng Điều này nếu bạn cố gắng nhiều):

public class UnsafeUtil {

    public static Unsafe unsafe;
    private static long fieldOffset;
    private static UnsafeUtil instance = new UnsafeUtil();

    private Object obj;

    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);

            unsafe = (Unsafe)f.get(null);
            fieldOffset = unsafe.objectFieldOffset(UnsafeUtil.class.getDeclaredField("obj"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}

20
đó là một mặt trời. * API không thực sự là một phần của ngôn ngữ Java trên mỗi se
DW.

Có một số phương thức gây tò mò khác trên Unsafe như tạo một đối tượng mà không gọi phương thức xây dựng, phương thức malloc / realloc / free.
Peter Lawrey

Tôi yêu đặc biệt là các getters và setters nguyên thủy trên các vị trí bộ nhớ, như putDouble (địa chỉ dài, gấp đôi d).
Daniel

42

Khi làm việc trong Swing tôi thích tính năng ẩn Ctrl- Shift- F1.

Nó kết xuất cây thành phần của cửa sổ hiện tại.
(Giả sử bạn không bị ràng buộc phím đó với thứ khác.)


1
Nhiều khả năng trình quản lý cửa sổ của bạn có một cái gì đó ràng buộc với khóa đó. Gnome không liên kết với nó, vì vậy tôi giả sử bạn đang chạy KDE, liên kết nó để 'chuyển sang máy tính để bàn 13'. Bạn có thể thay đổi nó bằng cách đi tới Bảng điều khiển, Vùng, Phím tắt và xóa ánh xạ cho Shift-Ctrl-F1
Devon_C_Miller

40

Mỗi tệp lớp bắt đầu với giá trị hex 0xCAFEBABE để xác định nó là mã byte JVM hợp lệ.

( Giải thích )


38

Phiếu bầu của tôi thuộc về java.util.conc hiện với các bộ sưu tập đồng thời và các trình thực thi linh hoạt cho phép các nhóm luồng khác, các tác vụ theo lịch trình và các tác vụ được phối hợp. DelayQueue là sở thích cá nhân của tôi, nơi các yếu tố được cung cấp sau một độ trễ được chỉ định.

java.util.Timer và TimerTask có thể được đưa vào phần còn lại một cách an toàn.

Ngoài ra, không chính xác ẩn nhưng trong một gói khác với các lớp khác liên quan đến ngày và thời gian. java.util.concản.TimeUnit rất hữu ích khi chuyển đổi giữa các nano giây, micro giây, mili giây và giây.

Nó đọc tốt hơn rất nhiều so với someValue * 1000 hoặc someValue / 1000 thông thường.


Gần đây được phát hiện CountDownLatchCyclicBarrier- rất hữu ích!
Raphael

37

Từ khóa khẳng định trình độ ngôn ngữ .


19
Vấn đề với khẳng định là nó cần phải được bật trong thời gian chạy.
extraneon

10
Nhưng nếu nó bị vô hiệu hóa thì dường như nó không ở đó. Bạn có thể thêm bao nhiêu xác nhận tùy thích vào mã của mình và bạn sẽ không có bất kỳ hình phạt hiệu suất nào nếu chúng bị vô hiệu hóa.
Ravi Wallau

5
Tôi tin rằng đó là một điều tốt về khẳng định: nó có thể bị tắt mà không bị phạt.
andref

vấn đề là, nếu bạn vô tình thực hiện một tác dụng phụ trong một xác nhận, bạn đã phải bật xác nhận để chương trình của bạn hoạt động ...
Chii

Để phát hiện nếu các xác nhận được bật, bạn có thể sử dụng {boolean assertsOn = false; khẳng định khẳng địnhOn = true; if (assertsOn) {/ * xác minh phức tạp * /}}. Điều này cũng cho phép đăng nhập hoặc ném ngoại lệ nếu trạng thái khẳng định không như mong đợi.
fernacolo

37

Không thực sự là một phần của ngôn ngữ Java, nhưng trình phân tách javap đi kèm với JDK của Sun không được biết đến hoặc sử dụng rộng rãi.


36

Việc bổ sung cấu trúc vòng lặp for cho mỗi vòng lặp trong 1.5. Tôi <3 nó.

// For each Object, instantiated as foo, in myCollection
for(Object foo: myCollection) {
  System.out.println(foo.toString());
}

Và có thể được sử dụng trong các trường hợp lồng nhau:

for (Suit suit : suits)
  for (Rank rank : ranks)
    sortedDeck.add(new Card(suit, rank));

Cấu trúc for-every cũng có thể áp dụng cho các mảng, trong đó nó ẩn biến chỉ số thay vì iterator. Phương thức sau đây trả về tổng của các giá trị trong một mảng int:

// Returns the sum of the elements of a
int sum(int[] a) {
  int result = 0;
  for (int i : a)
    result += i;
  return result;
}

Liên kết đến tài liệu của Sun


30
Tôi nghĩ rằng việc sử dụng iở đây là rất khó hiểu, vì hầu hết mọi người mong đợi tôi là một chỉ mục chứ không phải là thành phần mảng.
cdmckay

Vì vậy ... int sum (int [] mảng) {int result = 0; for (int phần tử: mảng) {result + = phần tử; } kết quả trả về; }
vẽ

28
Điều duy nhất khiến tôi bực mình về điều này là có vẻ như việc tạo một từ khóa để truy cập giá trị số vòng lặp thực sự rất dễ dàng, nhưng bạn không thể. Nếu tôi muốn lặp qua hai mảng và thay đổi thành một giây dựa trên các giá trị trong lần đầu tiên, tôi buộc phải sử dụng cú pháp cũ vì tôi không có phần bù vào mảng thứ hai.
Jherico

6
Thật xấu hổ vì nó cũng không hoạt động với En enations, giống như những thứ được sử dụng trong JNDI. Nó trở lại với các vòng lặp ở đó.
extraneon

3
@extraneon: hãy xem Bộ sưu tập.list (Bảng liệt kê <T> e). Điều đó sẽ giúp với việc liệt kê các vòng lặp trong vòng lặp foreach.
Werner Lehmann

34

Cá nhân tôi phát hiện ra java.lang.Voidrất muộn - cải thiện khả năng đọc mã kết hợp với thuốc generic, vdCallable<Void>


2
không hẳn. tại một số điểm, bạn cần phải cụ thể: Executors.newSingleThreadExecutor (). submit (new Callable <Void> () {..}) - bạn không thể khởi tạo một Callable mới <?> (), bạn cần chỉ định một loại rõ ràng - do đó, nó là một thay thế cho Callable <Object>.
Rahel Lüthy

4
Void cụ thể hơn Object vì Void chỉ có thể là null, Object có thể là bất cứ thứ gì.
Peter Lawrey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.