Tương đương với từ khóa C # 'var' trong Java là gì?


264

Một cách sử dụng từ khóa var trong C # là khai báo kiểu ẩn. Cú pháp tương đương Java cho var là gì?


4
val(hoặc var) nếu bạn sử dụng ngôn ngữ "thay thế Java" cụ thể ;-)

6
@pst: đó sẽ là Scala? Hừ, đúng vậy.
rsenna

Đối với IntelliJ, tôi đã gửi yêu cầu này như một yêu cầu tính năng: youtrack.jetbrains.com/su/IDEA-102808 IDE có thể thu gọn mã để hiển thị val hoặc var mặc dù mã bên dưới sẽ không có.
Jon Onstott

@Jon Tôi đã hack một cái gì đó cùng nhau cho IntelliJ, xem câu trả lời của tôi .
balpha

3
Hiện tại có một đề xuất cho tính năng này được đưa vào Java - openjdk.java.net/jeps/286
McGin 13/03/2016

Câu trả lời:


248

Chẳng có ai. Than ôi, bạn phải gõ tên đầy đủ.

Chỉnh sửa: 7 năm sau khi được đăng, nhập suy luận cho các biến cục bộ (với var) đã được thêm vào trong Java 10.

Chỉnh sửa: 6 năm sau khi được đăng, để thu thập một số ý kiến ​​từ bên dưới:

  • Lý do C # có vartừ khóa là vì có thể có các Loại không có tên trong .NET. Ví dụ:

    var myData = new { a = 1, b = "2" };

    Trong trường hợp này, không thể đưa ra một loại thích hợp myData. 6 năm trước, điều này là không thể trong Java (tất cả các loại đều có tên, ngay cả khi chúng cực kỳ dài dòng và không thông minh). Tôi không biết nếu điều này đã thay đổi trong thời gian trung bình.

  • varkhông giống như dynamic. variables vẫn được gõ tĩnh 100%. Điều này sẽ không biên dịch:

    var myString = "foo";
    myString = 3;
  • varcũng hữu ích khi loại rõ ràng từ bối cảnh. Ví dụ:

    var currentUser = User.GetCurrent();

    Tôi có thể nói rằng trong bất kỳ mã nào mà tôi chịu trách nhiệm, currentUserđều có một Userlớp hoặc dẫn xuất trong đó. Rõ ràng, nếu bạn thực hiện User.GetCurrenttrả lại một int, thì có lẽ đây là một bất lợi cho bạn.

  • Điều này không có gì để làm var, nhưng nếu bạn có hệ thống phân cấp thừa kế kỳ lạ nơi bạn che giấu các phương thức với các phương thức khác (ví dụ new public void DoAThing()), đừng quên rằng các phương thức không ảo bị ảnh hưởng bởi Loại mà chúng được sử dụng.

    Tôi không thể tưởng tượng một kịch bản trong thế giới thực, nơi đây là biểu hiện của thiết kế tốt, nhưng điều này có thể không hoạt động như bạn mong đợi:

    class Foo {
        public void Non() {}
        public virtual void Virt() {}
    }
    
    class Bar : Foo {
        public new void Non() {}
        public override void Virt() {}
    }
    
    class Baz {
        public static Foo GetFoo() {
            return new Bar();
        }
    }
    
    var foo = Baz.GetFoo();
    foo.Non();  // <- Foo.Non, not Bar.Non
    foo.Virt(); // <- Bar.Virt
    
    var bar = (Bar)foo;
    bar.Non();  // <- Bar.Non, not Foo.Non
    bar.Virt(); // <- Still Bar.Virt

    Như đã chỉ ra, các phương thức ảo không bị ảnh hưởng bởi điều này.

  • Không, không có cách nào không vụng về để khởi tạo varmà không có biến thực.

    var foo1 = "bar";        //good
    var foo2;                //bad, what type?
    var foo3 = null;         //bad, null doesn't have a type
    var foo4 = default(var); //what?
    var foo5 = (object)null; //legal, but go home, you're drunk

    Trong trường hợp này, chỉ cần làm theo cách cũ:

    object foo6;

11
@Mike Caron: C # có [mặc định] các cuộc gọi và nhà khai thác không ảo không phải là ảo nên ... var p = new X(); p.Z()không giống SuperX p = new X(); p.Z()với tất cả X và SuperX, mặc dù vậy X : SuperX. Với varcác tĩnh loại pluôn luôn là Xtrong ví dụ đầu tiên ở trên, nhưng luôn luôn SuperXtrong ví dụ thứ hai. Một sự khác biệt tinh tế nhưng quan trọng cần phải nhận thức. Nhưng câu trả lời của bạn rất chính xác :-)

200
@Jon Hanna: varkhông làm cho mã ít rõ ràng hơn. Thay vào đó là ý kiến ​​ngược lại. Tại sao ví dụ viết loại hai (hoặc thậm chí ba) lần trên cùng một hàng khi bạn khai báo và khởi tạo nó ( RadioButton radioButton = new RadioButton();)? varlàm cho bạn thay vì suy nghĩ hai lần khi bạn đặt tên cho các biến của mình bởi vì nó chuyển trọng tâm vào chức năng hơn là loại (ví dụ UserCollection collection = new userRepository.GetUsers();thay vì tự nhiên chuyển thành var users = userRepository.GetUsers();). Nếu bạn nghĩ varlà không rõ ràng thì đó chỉ là vì không sử dụng nó.
Martin Odhelius

4
@MartinOdhelius varrất chắc chắn có thể làm cho mã rõ ràng được sử dụng tốt, nhưng nó cũng có thể làm cho nó không rõ ràng được sử dụng quá tệ; giống như nhiều tùy chọn định dạng. Số dư khác nhau tùy thuộc vào mức độ bạn sử dụng các đối tượng và tổng quát ẩn danh, không có đối tượng nào tồn tại trong .NET 1.0, khiến nó không hữu dụng như một từ khóa giả định trong phiên bản đầu tiên của C♯. Tôi sẽ chỉ đặt tên cho một RadioButton radioButtontrường hợp của một phương thức của nhà máy hoặc người trợ giúp trong đó điều duy nhất có ý nghĩa về nút đó là nó RadioButton, nếu không thì đó là sự điên rồ có hoặc không có var.
Jon Hanna

6
@Jon Hanna: Tôi đã từng rất quan trọng varnhư bạn, nếu không hơn, nhưng tôi đã thay đổi ý kiến ​​của mình, và có lẽ nó đơn giản như một câu hỏi về những ý kiến ​​khác nhau, bởi vì tôi vẫn nghĩ bạn sai khi bạn nói đó là một cho dù bạn đang sử dụng các đối tượng ẩn danh và tổng quát bao nhiêu;) Khai báo kiểu thường chỉ là nhiễu mã, nếu bạn không thể hiểu mã mà không có mã thì có thể không rõ ràng trong cả hai trường hợp.
Martin Odhelius

3
Bạn đang nhầm lẫn var với các loại ẩn danh . varchính nó chỉ đơn giản yêu cầu trình biên dịch suy ra kiểu từ bài tập; đó là cú pháp đường. Tôi đã hoài nghi về nó lúc đầu, nhưng tôi sử dụng nó một cách tôn giáo và chưa gặp phải một thời gian mà nó gây ra sự nhầm lẫn. Nó loại bỏ sự dư thừa khi khởi tạo và loại bỏ sự cần thiết phải kiểm tra loại khi tham chiếu. Không có JAVA tương đương với JAVA 9.
Cướp

46

Nếu bạn thêm Lombok vào dự án của mình, bạn có thể sử dụng val của nó từ khóa .

http://projectlombok.org/features/val.html


1
@rightprint: Các đối tượng có tham chiếu finalkhông nhất thiết là bất biến. Hãy xem xétfinal StringBuilder strB = new StringBuilder("My reference is final"); strB.append("I'm not immutable");
Matthias Braun

1
Kể từ lombok v1.16.12, cũng có hỗ trợ thử nghiệm cho var. projectlombok.org/features/experimental/var.html
Roel Spilker

@MatthiasBraun ví dụ của bạn là sai. Trong trường hợp này, chính lớp StringBuilder là bất biến, bạn chỉ cần thêm giá trị chuỗi vào cấu trúc bên trong của nó bằng phương thức, điều này là hoàn toàn hợp pháp.
Andzej Maciusovic

27

JEP - Đề xuất cải tiến JDK

http://openjdk.java.net/jeps/286

JEP 286: Suy luận kiểu biến cục bộ

Tác giả Brian Goetz

// Goals:
var list = new ArrayList<String>();  // infers ArrayList<String>
var stream = list.stream();          // infers Stream<String>

Phiên bản nào của Java? 10?
Peter Mortensen

@PeterMortensen Có. JEP 286 đã được chấp nhận và xuất bản trong JDK 10 (xem 286 trong Tính năng tại openjdk.java.net/projects/jdk/10 ).
Justin Albano

20

Tôi đã tạo ra một plugin cho IntelliJ - theo một cách nào đó - cung cấp cho bạn vartrong Java. Đó là một hack, vì vậy các khuyến cáo từ chối thông thường được áp dụng, nhưng nếu bạn sử dụng IntelliJ để phát triển Java và muốn dùng thử, thì đó là tại https://bitbucket.org/balpha/varsity .


Thật tuyệt vời khi có một phím tắt để gập / mở các loại khai báo trong trình chỉnh sửa hiện tại. Plugin tuyệt vời mặc dù.
phím nóng

2
@hotkey Điều này sử dụng tính năng gấp mã tích hợp của IntelliJ, vì vậy bạn có thể mở ra mọi thứ với Ctrl-Shift-NumPadPlus. Khi con trỏ nằm trên một dòng chứa khai báo biến gấp, bạn có thể Ctrl-NumPadPlus và Ctrl-NumPadMinus để gập / mở các khai báo trong phương thức hiện tại. Gấp tất cả các khai báo là một chút khó xử, bạn đã gấp mọi thứ (Ctrl-Shift-NumPadMinus) và sau đó mở lại mọi thứ một lần nữa (Ctrl-Shift-NumPadPlus).
balpha

18

Với việc phát hành JDK 10 vào ngày 20 tháng 3, Java hiện bao gồm một vartên loại dành riêng (không phải là từ khóa mà xem bên dưới) như được chỉ định trong JEP 286 . Đối với các biến cục bộ, các biến sau đây hiện hợp lệ trong Java 10 trở lên:

var map = new HashMap<String, Integer>();

Tên varloại dành riêng trong Java gần giống với vartừ khóa trong C #, cả hai đều cho phép nhập ngầm (xem bên dưới để biết những khác biệt quan trọng). vartrong Java chỉ có thể được sử dụng cho suy luận kiểu ngầm định trong các ngữ cảnh sau (như được liệt kê trong JEP 286: Mục tiêu ):

  • biến cục bộ với khởi tạo
  • các chỉ mục trong vòng lặp for tăng cường
  • người dân địa phương khai báo theo vòng lặp truyền thống

Do đó, var không thể được sử dụng cho các trường, kiểu trả về, tên lớp hoặc tên giao diện. Cơ sở lý luận của nó là loại bỏ sự cần thiết phải bao gồm các tên loại dài khi khai báo và xác định các biến cục bộ, như đã nêu trong JEP 286 (tác giả Brian Goetz):

Chúng tôi tìm cách cải thiện trải nghiệm của nhà phát triển bằng cách giảm buổi lễ liên quan đến việc viết mã Java, đồng thời duy trì cam kết của Java về an toàn kiểu tĩnh, bằng cách cho phép các nhà phát triển bỏ qua tuyên bố thường không cần thiết về các loại biến cục bộ.

var Phạm vi trong Java

Cần lưu ý rằng đó varkhông phải là một từ khóa trong Java, mà là một tên loại dành riêng. Như trích dẫn từ JEP 286:

Mã định danh var không phải là một từ khóa; thay vào đó là một tên loại dành riêng. Điều này có nghĩa là mã sử dụng var làm biến, phương thức hoặc tên gói sẽ không bị ảnh hưởng; mã sử dụng var làm tên lớp hoặc tên giao diện sẽ bị ảnh hưởng (nhưng những tên này rất hiếm trong thực tế, vì chúng vi phạm các quy ước đặt tên thông thường).

Lưu ý rằng vì varlà tên loại dành riêng và không phải là từ khóa, nên nó vẫn có thể được sử dụng cho tên gói, tên phương thức và tên biến (cùng với vai trò can thiệp kiểu mới). Ví dụ, sau đây là tất cả các ví dụ về sử dụng hợp lệ vartrong Java:

var i = 0;
var var = 1;
for (var i = 0; i < 10; i++) { /* ... */ }
public int var() { return 0; }
package var;

Như trích dẫn từ JEP 286:

Điều trị này sẽ được giới hạn ở các biến cục bộ với các bộ khởi tạo, các chỉ mục trong vòng lặp for được tăng cường và các hàm cục bộ được khai báo trong một vòng lặp for truyền thống; nó sẽ không có sẵn cho các biểu mẫu phương thức, các biểu mẫu của hàm tạo, các kiểu trả về của phương thức, các trường, các biểu mẫu bắt hoặc bất kỳ loại khai báo biến nào khác.

Sự khác biệt giữa vartrong Java & C

Đây là một điểm khác biệt đáng chú ý giữa varC # và Java bao gồm: varcó thể được sử dụng làm tên loại trong C # nhưng không thể được sử dụng làm tên lớp hoặc tên giao diện trong Java. Theo tài liệu C # (Nhập ngầm định các biến cục bộ) :

Nếu một loại có tên varnằm trong phạm vi, thì vartừ khóa sẽ phân giải thành tên loại đó và sẽ không được coi là một phần của khai báo biến cục bộ được gõ ngầm.

Khả năng sử dụng varlàm tên loại trong C # tạo ra một số phức tạp và đưa ra một số quy tắc phân giải phức tạp, được tránh vartrong Java bằng cách không cho phép varlàm tên lớp hoặc giao diện. Để biết thông tin về độ phức tạp của vartên loại trong C #, hãy xem Hạn chế áp dụng cho khai báo biến được nhập ngầm định . Để biết thêm thông tin về lý do đằng sau quyết định phạm vi cho `var trong Java, hãy xem JEP 286: Lựa chọn phạm vi .


Có sự khác biệt nào giữa Java và c # mà bạn không thể sử dụng varcho các trường hoặc các kiểu trả về không? Tại sao nó quan trọng cần lưu ý?
dùng1306322

@ user1306322 Trong bối cảnh đó, không. vartrong Java không thể được sử dụng cho các trường hoặc các kiểu trả về. Điều này rất quan trọng vì hạn chế này làm cho varngữ cảnh nhạy cảm, nơi nó chỉ có thể được sử dụng trong một số bối cảnh (biến cục bộ) chứ không phải các bối cảnh khác. Đây không nhất thiết là một sự khác biệt giữa Java và C # cần lưu ý, nhưng nói chung là một hạn chế quan trọng khi sử dụng vartrong Java.
Justin Albano

Tôi chỉ nhìn lên và có vẻ như trong c # bạn có thể tạo varmột tên lớp và sử dụng nó như vậy. Về mặt kỹ thuật, đây là một "từ khóa ngữ cảnh" trong trường hợp c #, nhưng trong Java dường như bạn không thể làm như vậy. Sửa tôi nếu tôi sai.
dùng1306322

1
Bạn nói đúng. Bạn không thể sử dụng varlàm tên lớp hoặc tên giao diện trong Java (dù sao nó không phổ biến), nhưng bạn có thể sử dụng nó cho tên biến, tên phương thức và tên gói. Ví dụ, var var = 1;là một câu lệnh Java hợp lệ nhưng cố gắng khai báo một lớp là public class var {}kết quả trong một lỗi : as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations. Tôi đã cập nhật câu trả lời ở trên để đi sâu vào chi tiết hơn về lý do đằng sau vartrong Java và sự khác biệt của nó vớivar C #.
Justin Albano

11

Nó sẽ được hỗ trợ trong JDK 10. Thậm chí có thể thấy nó hoạt động trong bản dựng truy cập sớm .

Các JEP 286 :

Tăng cường Ngôn ngữ Java để mở rộng suy luận kiểu đối với khai báo các biến cục bộ với các bộ khởi tạo.

Vì vậy, bây giờ thay vì viết:

List<> list = new ArrayList<String>();
Stream<> stream = myStream();

Bạn viết:

var list = new ArrayList<String>();
var stream = myStream();

Ghi chú:

  • varbây giờ là một tên loại dành riêng
  • Java vẫn còn cam kết gõ tĩnh!
  • Nó chỉ có thể được sử dụng tại địa phương khai báo biến

Nếu bạn muốn dùng thử mà không cần cài đặt Java trên hệ thống cục bộ của mình, tôi đã tạo một hình ảnh Docker với JDK 10 được cài đặt trên nó:

$ docker run -it marounbassam/ubuntu-java10 bash
root@299d86f1c39a:/# jdk-10/bin/jshell
Mar 30, 2018 9:07:07 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
|  Welcome to JShell -- Version 10
|  For an introduction type: /help intro

jshell> var list = new ArrayList<String>();
list ==> []

3
Coi chừng, mã bạn cung cấp (trước / sau var) không tương đương. Trong varví dụ listlà loại ArrayList, không phải là mộtList .
Gili

8

Một giải pháp đơn giản (giả sử bạn đang sử dụng một IDE tốt) là chỉ cần nhập 'int' ở mọi nơi và sau đó lấy nó để đặt loại cho bạn.

Tôi thực sự vừa thêm một lớp gọi là 'var' vì vậy tôi không phải gõ một cái gì đó khác.

Mã vẫn còn quá dài dòng, nhưng ít nhất bạn không phải gõ nó!


Khi bạn nói "IDE tốt" là Eclipse * bị loại trừ? - điều này dường như không hoạt động trong Luna (ít nhất là khi tôi mới thử nó int) - tôi có thiếu điều gì không? (*: trong khi tôi sẽ không bao giờ gọi Eclipse là một IDE tốt, tôi không thể phán xét cho người khác ...)
BrainSlugs83

@ BrainSlugs83 dunno Tôi đang sử dụng IDEA, không thực sự sử dụng nhật thực trước đây. Nó không đúng loại cho bạn? Tôi đã quen với c # / visual studio / resharper giống như IDEA ngoại trừ nó thực sự hoạt động bình thường! Trong tất cả các máy bay phản lực, bạn có thể nhấn alt-enter để nhận danh sách đề xuất khi có lỗi - vì vậy, cài đặt kiểu int sẽ giới thiệu một lỗi mà bạn có thể nhập vào và lấy nó để sắp xếp loại
JonnyRaa

5

Bạn có thể xem qua Kotlin bởi JetBrains, nhưng đó là giá trị. không var.


4
Kotlin có val và var. val tương đương với việc khai báo một biến cuối cùng trong java, var cho phép gán lại.
samlewis

5

Java 10 đã nhận được suy luận kiểu biến cục bộ, vì vậy bây giờ nó có var tương đối giống với C # one (theo như tôi biết).

Nó cũng có thể suy ra loại phi denotable (loại trong nước chưa thể có tên trong đó diễn ra bởi các lập trình viên, mặc dù trong đó loại đều là phòng không denotable là khác nhau). Xem ví dụ: Thủ thuật với varvà các lớp ẩn danh (mà bạn không bao giờ nên sử dụng tại nơi làm việc) .

Sự khác biệt tôi có thể tìm thấy là trong C #,

Nếu một loại có tên var nằm trong phạm vi, thì từ khóa var sẽ phân giải thành tên loại đó và sẽ không được coi là một phần của khai báo biến cục bộ được gõ ngầm.

Trong Java 10 varkhông phải là một tên loại hợp pháp.


@Lii Vâng, tôi không nhớ những gì tôi muốn nói ở đây, đã bị xóa.
Alexey Romanov

Tuyệt quá! Sẽ xóa bình luận của tôi để dọn dẹp lịch sử!
Lii

4

Tính đến Java 10, tương đương là ... var.


bất kỳ sự khác biệt? Tôi có nghĩa là bạn biết tốt hơn là viết câu trả lời ngắn như thế này, những gì với cấp độ đại diện của bạn n tất cả. Và chắc chắn phải có một số khác biệt.
dùng1306322

@ user1306322 Đó là một câu hỏi hoàn toàn riêng biệt! Bạn có thể kiểm tra thẻ java-10, vì nhiều khía cạnh của điều này đã được yêu cầu.
Brian Goetz

Vâng, đây là những câu hỏi để xem nếu bạn đang googling này, vì nó đến trước và được liên kết với trong mỗi bài có liên quan trong thanh bên. Vì vậy, tôi cho rằng nếu bạn biết câu hỏi riêng biệt trả lời nó, ít nhất bạn có thể liên kết với nó hoặc bao gồm các phần của câu hỏi vào câu trả lời của bạn.
dùng1306322

3

Tôi biết cái này cũ hơn nhưng tại sao không tạo một lớp var và tạo các hàm tạo với các kiểu khác nhau và tùy thuộc vào các hàm tạo nào được gọi mà bạn nhận var với kiểu khác. Bạn thậm chí có thể xây dựng các phương thức để chuyển đổi loại này sang loại khác.


3

Lombokhỗ trợ var nhưng nó vẫn được phân loại là thử nghiệm:

import lombok.experimental.var;

var number = 1; // Inferred type: int
number = 2; // Legal reassign since var is not final
number = "Hi"; // Compilation error since a string cannot be assigned to an int variable
System.out.println(number);

Đây là một cạm bẫy cần tránh khi cố gắng sử dụng nó trong IntelliJ IDEA. Nó dường như hoạt động như mong đợi mặc dù bao gồm hoàn thành tự động và mọi thứ. Cho đến khi có một giải pháp "không hack" (ví dụ do JEP 286: Suy luận kiểu biến cục bộ ), đây có thể là lựa chọn tốt nhất của bạn ngay bây giờ.

Lưu ý rằng valcũng được hỗ trợ Lombokmà không sửa đổi hoặc tạo một lombok.config.


2

Bạn có thể, trong Java 10, nhưng chỉ dành cho Cục bộ biến, ý nghĩa,

Bạn có thể,

var anum = 10; var aString = "Var";

Nhưng không thể,

var anull = null; // Since the type can't be inferred in this case

Kiểm tra thông số kỹ thuật để biết thêm.


2
Điều này là không đúng. varcó thể được sử dụng cho nhiều dạng loại không thể khử được, bao gồm loại chụp, loại giao cắt và loại lớp ẩn danh. Và, kể từ Java 11, nó cũng có thể được áp dụng cho các tham số lambda.
Brian Goetz

0

Nói chung, bạn có thể sử dụng lớp Object cho bất kỳ loại nào, nhưng bạn đã thực hiện truyền kiểu sau!

ví dụ:-

Object object = 12;
    Object object1 = "Aditya";
    Object object2 = 12.12;

    System.out.println(Integer.parseInt(object.toString()) + 2);

    System.out.println(object1.toString() + " Kumar");
    System.out.println(Double.parseDouble(object2.toString()) + 2.12);

Aditya, xin vui lòng kiểm tra tất cả các câu trả lời khác của bạn. Nhiều người trong số họ có -1 và có lẽ vì một lý do tốt. Đừng đăng bất cứ điều gì nếu bạn không chắc chắn nó đúng.
dùng1306322

@ user1306322 vấn đề trong câu trả lời của tôi là gì! bạn có thể giải thích? chúng ta không thể sử dụng lớp Object cho tất cả các loại dữ liệu?
Aditya Kumar

Đối tượng = 12; Đối tượng1 = "Aditya"; Đối tượng2 = 12,12; System.out.println (Integer.parseInt (object.toString ()) + 2); System.out.println (object1.toString () + "Kumar"); System.out.println (Double.parseDouble (object2.toString ()) + 2.12);
Aditya Kumar

Vấn đề là bạn đã không hiểu câu hỏi. Câu hỏi không phải là "làm thế nào để thực hiện công việc này", mà là "có một thứ như thế này". Bạn trả lời sai câu hỏi. Với vartừ bây giờ chính thức trong ngôn ngữ, câu trả lời của bạn cũng đề cập đến cách thức lỗi thời.
dùng1306322

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.