Có cách nào ngắn gọn và thú vị để tạo một List<Integer>
, hoặc có thể là Integer[]
hoặc int[]
, với các giá trị tuần tự từ một số start
giá trị đến mộtend
giá trị nào đó không?
Đó là, một cái gì đó ngắn hơn, nhưng tương đương với 1 cái sau:
void List<Integer> makeSequence(int begin, int end) {
List<Integer> ret = new ArrayList<>(end - begin + 1);
for (int i=begin; i<=end; i++) {
ret.add(i);
}
return ret;
}
Việc sử dụng ổi cũng được.
Cập nhật:
Phân tích hiệu suất
Vì câu hỏi này đã nhận được một số câu trả lời tốt, cả hai đều sử dụng Java 8 bản địa và các thư viện của bên thứ ba, tôi nghĩ tôi sẽ kiểm tra hiệu suất của tất cả các giải pháp.
Bài kiểm tra đầu tiên chỉ đơn giản là kiểm tra việc tạo danh sách 10 phần tử [1..10]
bằng các phương pháp sau:
- classicArrayList : mã được đưa ra ở trên trong câu hỏi của tôi (và về cơ bản giống với câu trả lời của adarshr).
- eclipseCollections : mã được đưa ra trong câu trả lời của Donald bên dưới sử dụng Eclipse Collections 8.0.
- ổiRange : mã được đưa ra trong câu trả lời của daveb bên dưới. Về mặt kỹ thuật, điều này không tạo ra
List<Integer>
mà là mộtContiguousSet<Integer>
- nhưng vì nó thực hiệnIterable<Integer>
theo thứ tự, nó hầu hết hoạt động cho các mục đích của tôi. - intStreamRange : mã được đưa ra trong câu trả lời của Vladimir bên dưới, sử dụng
IntStream.rangeClosed()
- được giới thiệu trong Java 8. - streamIterate : mã được đưa ra trong câu trả lời của Catalin bên dưới, mã này cũng sử dụng
IntStream
chức năng được giới thiệu trong Java 8.
Dưới đây là kết quả tính bằng kilo-thao tác trên giây (số càng cao càng tốt), cho tất cả những điều trên với danh sách kích thước 10:
... và một lần nữa đối với danh sách có kích thước 10.000:
Biểu đồ cuối cùng đó là chính xác - các giải pháp khác ngoài Eclipse và Guava quá chậm để có được một thanh pixel duy nhất! Các giải pháp nhanh nhanh hơn 10.000 đến 20.000 lần so với các giải pháp còn lại.
Tất nhiên, điều đang xảy ra ở đây là các giải pháp ổi và eclipse không thực sự hiện thực hóa bất kỳ loại danh sách 10.000 phần tử nào - chúng chỉ đơn giản là các trình bao bọc có kích thước cố định xung quanh điểm đầu và điểm cuối. Mỗi phần tử được tạo khi cần thiết trong quá trình lặp. Vì chúng tôi không thực sự lặp lại trong thử nghiệm này, nên chi phí được hoãn lại. Tất cả các giải pháp khác thực sự hiện thực hóa danh sách đầy đủ trong bộ nhớ và phải trả giá đắt trong một tiêu chuẩn chỉ dành cho sáng tạo.
Hãy làm điều gì đó thực tế hơn một chút và cũng lặp lại trên tất cả các số nguyên, tính tổng chúng. Vì vậy, trong trường hợp của IntStream.rangeClosed
biến thể, điểm chuẩn trông giống như:
@Benchmark
public int intStreamRange() {
List<Integer> ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());
int total = 0;
for (int i : ret) {
total += i;
}
return total;
}
Ở đây, các bức tranh thay đổi rất nhiều, mặc dù các giải pháp không hiện thực hóa vẫn là nhanh nhất. Đây là độ dài = 10:
... và length = 10.000:
Quá trình lặp lại lâu trên nhiều phần tử làm mọi thứ trở nên hoàn thiện hơn, nhưng nhật thực và ổi vẫn nhanh hơn gấp đôi ngay cả trong bài kiểm tra 10.000 phần tử.
Vì vậy, nếu bạn thực sự muốn List<Integer>
, các bộ sưu tập nhật thực có vẻ là lựa chọn tốt nhất - nhưng tất nhiên nếu bạn sử dụng các luồng theo cách nguyên bản hơn (ví dụ: quên .boxed()
và giảm miền nguyên thủy) có thể bạn sẽ kết thúc nhanh hơn tất cả những các biến thể.
1 Có lẽ ngoại trừ việc xử lý lỗi, ví dụ: nếu end
< begin
, hoặc nếu kích thước vượt quá một số giới hạn triển khai hoặc JVM (ví dụ: mảng lớn hơn 2^31-1
.