Java có các kiểu có thể thay đổi cho Integer, Float, Double, Long không?


81

Tôi đang ở trong một tình huống mà tôi muốn sử dụng các phiên bản có thể thay đổi của những thứ như Số nguyên. Tôi có phải sử dụng các lớp này (bên dưới) hay Java có thứ gì đó được tích hợp sẵn không?

http://www.java2s.com/Code/Java/Data-Type/Amutableintwrapper.htm


8
Câu hỏi là tại sao bạn muốn làm điều này?
helpermethod

2
Đối với một số trường hợp (ví dụ: một trò chơi, lưu trữ một phần thức ăn chứa ncalo, có thể bị cạn kiệt / thêm vào), có thể tốt hơn nếu sử dụng một lớp được đặt tên theo cách sử dụng, (ví dụ: class FoodItem { int calories; }vì nó rõ ràng hơn và các phương thức có thể được bổ sung nếu cần thiết sau này.
GKFX

7
Java 8 lambdas chỉ hoạt động với các biến cuối cùng hiệu quả. Để khắc phục hạn chế này, cần có một int có thể thay đổi.
Alex

Bạn có thể muốn một bộ đếm cần được chuyển giữa các phương thức. Việc chuyển một intkhông hoạt động như thể nó được tăng lên trong một phương thức thì giá trị sẽ không được phản ánh trong phương thức kia.
Adam Burley

Câu trả lời:


51

Không, Java không tích hợp sẵn những thứ này. Và đó là lý do. Sử dụng các loại có thể thay đổi rất nguy hiểm, vì chúng có thể dễ dàng bị lạm dụng. Ngoài ra, nó thực sự dễ dàng để thực hiện nó. Ví dụ, commons-lang có một MutableInt.


5
Tôi đoán là Integer của nhà phát triển java muốn 'cư xử' giống như một int, nghĩa là..chỉ cần bạn có tham chiếu đến nó, nó không bao giờ thay đổi (tránh nhầm lẫn). Nhưng..vẫn có vẻ kỳ lạ khi không có tùy chọn có thể thay đổi bằng cách nào đó, đối với tôi ...
rogerdpack

35
"Sử dụng các loại có thể biến đổi rất nguy hiểm vì chúng có thể dễ dàng bị lạm dụng." Hầu hết mọi thứ có thể được sử dụng sai. Các kiểu bất biến tồn tại cho các trường hợp mà an toàn là quan trọng, mặc dù chúng có thể được thay đổi bằng phản xạ. Với những trường hợp đó, không có lý do gì để ngăn mọi người sử dụng các loại có thể biến đổi khi họ cần.
GKFX

2
Một cách tốt hơn để nói, các kiểu bất biến tạo ra ít nhầm lẫn hơn trong các bản đồ và tập hợp. Nếu bạn có một Số nguyên có thể thay đổi và thay đổi giá trị của nó nơi nó được dùng làm khóa, nó sẽ làm rối tung bộ sưu tập. Tuy nhiên, trong trường hợp bạn cần một số triển khai Integer có thể thay đổi, không gì dễ dàng hơn là tạo một số lớp có giá trị int bên trong. Và bạn có thể sáng tạo ở đó - làm cho nó ví dụ như Bộ đếm hoặc Đếm ngược, không chỉ là một số nguyên đơn thuần có thể kích hoạt mọi thứ. Cung cấp cho nó một số logic (trừ khi bạn phát triển trong Java EE hoạt động từ dưới lên).
Vlasec

Chắc chắn là một câu hỏi cũ, nhưng hy vọng ai đó có thể trả lời LÀM THẾ NÀO chúng có thể bị sử dụng sai. Điều gì là nguy hiểm khi sử dụng chúng?
The Fluffy Robot

@ user1175807 Như Vlasec đã nhận xét, nếu bạn vô tình sửa đổi một biến mà bạn đã sử dụng ở một nơi khác, nó sẽ gây ra lỗi kỳ lạ. Tệ hơn nữa, giả sử bạn đang viết một chương trình hoạt động cùng với mã của khách hàng. Bạn cần triển khai một phương thức có tham số kiểu Số nguyên có thể thay đổi. Bây giờ nếu bạn sửa đổi Số nguyên có thể thay đổi vì bất kỳ lý do gì, thì nó cũng sẽ bị thay đổi trong chương trình của khách hàng, điều này hoàn toàn không mong muốn và sẽ gây ra lỗi khó tìm.
GregT

90

Bạn luôn có thể bọc giá trị trong một mảng như int[] mutable = {1};thể nếu bao gồm mã cho một lớp trình bao bọc có thể thay đổi là quá cồng kềnh.


30
Thông minh, lỗi xấu như tội lỗi.
gvlasov

2
điều này là siêu thông minh và hầu như không tốn không gian. đồng thời tránh được quá trình đồng bộ hóa được thực hiện với AtomicInt.
CompEng88

52

Kể từ khi JDK 1.5 java bây giờ có java.util.concurrent.atomic.AtomicInteger

Đây là một số nguyên có thể thay đổi an toàn trong chuỗi, ví dụ về việc sử dụng:

final AtomicInteger value = new AtomicInteger(0);

sau đó về sau:

value.incrementAndGet();

12
Sự an toàn này đi kèm với chi phí hiệu suất, trong nhiều trường hợp là không cần thiết. Ví dụ, một trường hợp sử dụng phổ biến đối với tôi là tăng một bộ đếm được bắt bởi lambda. Sử dụng nguyên tử là quá mức cần thiết.
Minas Mina

12

Đây là một lớp nhỏ tôi đã tạo cho một số nguyên có thể thay đổi:

public class MutableInteger {
    private int value;
    public MutableInteger(int value) {
        this.value = value;
    }
    public void set(int value) {
        this.value = value;
    }
    public int intValue() {
        return value;
    }
}

Bạn có thể dễ dàng mở rộng điều này cho bất kỳ nguyên thủy nào khác. Tất nhiên, giống như mọi người vẫn nói, bạn nên sử dụng nó một cách cẩn thận.


1
IMHO là lựa chọn tốt nhất vì nó không đưa ra manh mối sai lệch về đồng thời như sử dụng bộ liên kết nguyên tử. Và một mảng, thực sự tôi sẽ không bao giờ làm điều tồi tệ như vậy trong mã của mình ..;)
Snicolas

Có thể là một ý tưởng tốt để cung cấp một lớp wrapper chung duy nhất thay vì để bạn không kết thúc với một MutableInteger, MutableDouble, MutableStringvv nhưng thay vì có một Mutable<Integer>, Mutable<Double>... Các chi phí bộ nhớ (sử dụng Integertrên intthường sẽ không rơi vào tài khoản. Tuy nhiên, bạn nhận được một duy nhất, sẵn sàng để sử dụng lớp đó có thể xử lý hầu hết các trường hợp (Nếu bạn muốn số nguyên của bạn để có những điều tương tự hoặc tương tự bạn vẫn cần phải phân lớp, mặc dù).
Qw3ry

Có thể là một ý kiến ​​hay nếu bạn mở rộng Số .
Stijn de Witt

7

Bạn có thể sử dụng nnnn [] làm đối tượng có thể thay đổi cho bất kỳ kiểu nguyên thủy nào như @Alexandre gợi ý, java cũng có AtomicInteger và AtomicLong.

IMHO int thường là một lựa chọn tốt hơn Integer và có thể thay đổi.

Bạn có thể biết thêm chi tiết về lý do tại sao bạn cần một đối tượng biến đổi, có lẽ có một cách khác để đạt được điều tương tự.


8
int không thể thay đổi.
mjaggard,

7
intluôn luôn là có thể thay đổi trừ khi cũng của nófinal
Peter Lawrey

18
Không thực sự hợp lệ khi nói rằng một kiểu nguyên thủy có thể thay đổi được . Nó có thể được thay đổi nhưng mọi đối tượng không phải cuối cùng cũng vậy nếu bạn chỉ trỏ đến một đối tượng mới. Ví dụ Integer a = 4;sau đó a = 5;là mã hợp lệ, nhưng Integerkhông thể thay đổi.
mjaggard

Tôi đồng ý rằng các Integerphiên bản không thể thay đổi ngay cả khi các tham chiếu đến chúng, nhưng đó là một kiểu khác.
Peter Lawrey

1
intkhông thể thay đổi bởi vì nếu bạn chuyển nó cho một phương thức, không có cách nào để phương thức thay đổi giá trị của nó và có giá trị mới được phản ánh trong phương thức gọi
Adam Burley

5

AtomicIntegerđã được đề cập. Mutable Doubles có thể được mô phỏng với AtomicReference<Double>. Các cảnh báo đã đề cập được áp dụng và đó là kiểu không hợp lệ, nhưng đôi khi bạn có mã như thế này

double sum=0
for (Data data:someListGenerator())
  sum+=data.getValue()

và muốn cấu trúc lại nó theo kiểu Java 8 chức năng. Nếu mã tuân theo mô hình này nhưng thêm độ phức tạp đáng kể vào nó, thì chuyển đổi hợp lý nhất có thể

AtomicReference<Double> sumref=new AtomicReference<>(0d);
someStreamGenerator().forEach(data->
  sumref.set(sumref.get().doubleValue()+data.getValue()));
double sum=sumref.get().doubleValue();

Tất nhiên, đây ít nhất là phong cách đáng nghi vấn. Nhưng tôi đã nhiều lần thấy mình ở trong một tình huống với một vòng lặp xoắn trên ResultSetmáy tính và một phần tích lũy ba thông tin khác nhau từ nó. Điều này làm cho nó thực sự khó khăn để chuyển đổi mã thành phong cách chức năng thích hợp. Việc chuyển đổi các bộ phận tích hợp theo mô hình trên đối với tôi dường như là một sự cân bằng hợp lý giữa mã sạch và tái cấu trúc đơn giản hóa quá mức.


Bạn thực sự nên suy nghĩ về cách diễn đạt của mình: Ngay cả khi bạn sử dụng lambda, ví dụ của bạn cũng không hoạt động , vì điều đó cấm các tác dụng phụ. Nếu bạn thực sự viết nó chức năng, bạn không cần phải mutables: someStreamGenerator().mapToDouble(Data::getValue).sum(). Ngay cả khi tích hợp ba thông tin khác nhau, vẫn có một cách chức năng bằng cách sử dụng Stream.reducehoặc Stream.collect. Tôi thấy không có lý do gì để cấu trúc lại mọi vòng lặp thành một đoạn mã chức năng, nhưng nếu bạn muốn đi theo cách đó, bạn nên làm cho đến khi kết thúc.
Tobias Liefke

Như tôi đã viết: Đây không phải là phong cách thích hợp và đối với mỗi và bất kỳ mã mới nào, điều này không nên được sử dụng. Nhưng khi cấu trúc lại hơn 400.000 dòng mã đã phát triển trong vòng hơn 15 năm, bạn thấy các cấu trúc mà việc viết lại đúng cách thành các cấu trúc chức năng thực sự có thể cực kỳ khó khăn. Sau đó, viết lại theo kiểu kết hợp như vậy có thể là một sự đánh đổi hợp lý vì bạn có được ít nhất cấu trúc cơ bản phù hợp. forforeachcó thể là một phần của các khuôn khổ phức tạp được viết lại theo chức năng, vì vậy bạn phải căn chỉnh phần còn lại của mã bằng cách nào đó xung quanh chúng.
Dirk Hillbrecht

Bạn đang nhầm lẫn giữa lambdas và lập trình hàm. Trong ví dụ của bạn, bạn đã không viết lại nó "chức năng". Và có ích gì khi viết lại mọi thứ bằng lambdas, khi bạn mất khả năng đọc, nhưng không có được những lợi thế của lập trình hàm? Tại sao người ta nên cố gắng loại bỏ mọi vòng lặp trong một khuôn khổ phức tạp bằng cách sử dụng các phép lai như vậy?
Tobias Liefke

Bạn có 1000 địa điểm với một thành ngữ nhất định trong mã của mình. Thành ngữ được điều khiển bởi một thư viện hoặc bất kỳ cấu trúc toàn cục nào. Bạn thay thế cấu trúc toàn cục đó bằng một cấu trúc mới dựa trên cách tiếp cận chức năng và lambdas. 998 trong số 1000 địa điểm của bạn có thể được chuyển đổi rõ ràng thành phong cách chức năng. 2 cái còn lại cực kỳ khó chuyển đổi cho hợp lý. Trong những trường hợp như vậy, tôi luôn yêu cầu chuyển đổi sang phong cách mới với các cấu trúc lai như vậy. Chỉ khi đó, bạn mới có thể loại bỏ bất kỳ cấu trúc toàn cục cũ nào đã có trong mã. Mặc dù không được hoàn hảo, nhưng chất lượng mã tổng thể sẽ tăng lên.
Dirk Hillbrecht

2

Bạn có thể nhập gói org.omg.CORBA (hoặc chỉ lớp bạn cần) và trong đó bạn có thể sử dụng các lớp Holder.

Ví dụ: nó có "IntHolder" trong đó trường nơi nó lưu trữ số nguyên là công khai, cấp quyền truy cập để sửa đổi nó.

public static void triple(IntHolder x){
    x.value = 3 * x.value;
}

IntHolder mutableInt = new IntHolder(10);
triple(mutableInt);     
System.out.println(mutableInt.value);

Nó cũng có "LongHolder" và "DoubleHolder" và rất nhiều thứ khác mà bạn có thể sử dụng. Sử dụng cẩn thận.

Đây là api cho nó: https://docs.oracle.com/javase/7/docs/api/org/omg/CORBA/package-summary.html


2
Mặc dù là cách rất thông minh để khắc phục sự cố, nhưng với Java9 sắp ra mắt, bạn có thể không muốn sử dụng điều này - điều này sẽ nhập toàn bộ mô-đun CORBA chỉ dành cho người giữ int.
Agoston Horvath
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.