Java: có chức năng bản đồ không?


140

Tôi cần một chức năng bản đồ . Có cái gì đó như thế này trong Java chưa?

(Dành cho những ai thắc mắc: Tất nhiên tôi biết cách tự mình thực hiện chức năng tầm thường này ...)


1
Nếu không, việc xác định chính mình là chuyện nhỏ. Nhưng tôi cho rằng google biết hàng tá triển khai?

2
Sao y (khá tốt hơn) tại stackoverflow.com/questions/3907412/
Khăn

6
@Chris: Làm thế nào là cùng một câu hỏi?
Albert

1
Nếu câu trả lời cho câu hỏi này là có, thì nó cũng trả lời cho câu hỏi được liên kết khác. Nếu câu trả lời là không (và có vẻ như vậy), chúng hoàn toàn không liên quan.
Albert

1
Kể từ Java8, đây là những gì @delnan có thể đã đề cập đến leveluplunch.com/java/examples/ ám
Eternalcode

Câu trả lời:


86

Không có khái niệm về một hàm trong JDK như java 6.

Quả ổi có giao diện Chức năng và phương thức cung cấp chức năng bạn yêu cầu.
Collections2.transform(Collection<E>, Function<E,E2>)

Thí dụ:

// example, converts a collection of integers to their
// hexadecimal string representations
final Collection<Integer> input = Arrays.asList(10, 20, 30, 40, 50);
final Collection<String> output =
    Collections2.transform(input, new Function<Integer, String>(){

        @Override
        public String apply(final Integer input){
            return Integer.toHexString(input.intValue());
        }
    });
System.out.println(output);

Đầu ra:

[a, 14, 1e, 28, 32]

Ngày nay, với Java 8, thực sự có một hàm bản đồ, vì vậy tôi có thể viết mã theo cách ngắn gọn hơn:

Collection<String> hex = input.stream()
                              .map(Integer::toHexString)
                              .collect(Collectors::toList);

8
Điều đáng chú ý là trong khi với Guava, bạn có thể làm điều này, bạn có thể không muốn: code.google.com/p/guava-lologists/wiki/FeftalExplained (đọc phần "Caveats").
Adam Parkin

2
@AdamParkin đúng, nhưng tôi khá chắc chắn đề cập đến các khái niệm chức năng nâng cao hơn so với điều này, nếu không họ sẽ không phát triển các phương thức biến đổi ( ) ở nơi đầu tiên
Sean Patrick Floyd

2
Trên thực tế, không, thường có một hiệu suất rõ ràng với các thành ngữ chức năng, đó là lý do tại sao họ nhấn mạnh bạn chỉ nên sử dụng các phương tiện nếu bạn chắc chắn đáp ứng hai tiêu chí được nêu ra: tiết kiệm ròng LỘC cho toàn bộ cơ sở mã hóa và đã được chứng minh tăng hiệu suất do đánh giá lười biếng (hoặc ít nhất là không đạt hiệu suất). Không tranh cãi về việc sử dụng chúng, chỉ cho biết rằng nếu bạn đang đi, bạn nên chú ý đến các cảnh báo của những người thực hiện.
Adam Parkin

4
@SeanPatrickFloyd bây giờ đã hết Java 8, muốn cập nhật điều này với một ví dụ liên quan đến lambdas? Giống nhưCollections2.transform(input -> Integer.toHexString(intput.intValue())
Daniel Lubarov

2
@Daniel Trong Java 8, tôi không thấy lý do để làm điều đó với Guava. Thay vào đó tôi sẽ đi tìm câu trả lời của leventov
Sean Patrick Floyd

92

Kể từ Java 8, có một số tùy chọn tiêu chuẩn để thực hiện điều này trong JDK:

Collection<E> in = ...
Object[] mapped = in.stream().map(e -> doMap(e)).toArray();
// or
List<E> mapped = in.stream().map(e -> doMap(e)).collect(Collectors.toList());

Xem java.util.Collection.stream()java.util.stream.Collectors.toList().


140
Điều này là quá nhiều dài dòng làm tổn thương tôi bên trong.
Natix

1
@Natix đồng ý về toList(). Thay thế bằng loại khác:(List<R>)((List) list).replaceAll(o -> doMap((E) o));
leventov

2
Có thể e -> doMap(e)được thay thế bằng chỉ doMap?
jameshfisher

3
@jameshfisher, vâng, một cái gì đó như foo::doMaphoặc Foo::doMap.
leventov

9
Tôi đoán đây là lý do Scala tồn tại. Đợi Java 12 có cái gì đó có thể đọc được.
JulienD

26

Có một thư viện tuyệt vời tên là Java chức năng xử lý nhiều thứ bạn muốn Java có nhưng nó không có. Một lần nữa, Scala cũng có ngôn ngữ tuyệt vời này thực hiện mọi thứ Java nên làm nhưng không tương thích với mọi thứ được viết cho JVM.


Tôi quan tâm đến cách họ kích hoạt cú pháp sau: a.map({int i => i + 42});họ có mở rộng trình biên dịch không? hoặc thêm tiền xử lý?
Andrey

@Andrey - Bạn có thể tự hỏi họ hoặc kiểm tra mã nguồn để xem cách thực hiện. Đây là một liên kết đến nguồn: functionjava.org/source
Wheaties

1
@Andrey: ví dụ sử dụng cú pháp từ đề xuất đóng cửa BGGA. Mặc dù đang chạy nguyên mẫu, nhưng nó chưa có trong Java 'chính thức'.
Peter tibraný

@Andrey: cú pháp đó là một phần của một đặc tả được đề xuất cho các bao đóng trong Java (xem đoạn thứ hai đến cuối cùng trên trang chủ). Chỉ có một triển khai nguyên mẫu.
Michael Borgwardt

2
Trộm chủ đề Scala :( Tôi hy vọng SO sẽ không trở thành như danh sách gửi thư của JavaPosse;)
Jorn

9

Hãy cẩn thận với Collections2.transform()ổi. Ưu điểm lớn nhất của phương pháp đó cũng là mối nguy hiểm lớn nhất của nó: sự lười biếng.

Nhìn vào tài liệu Lists.transform()mà tôi tin rằng cũng áp dụng cho Collections2.transform():

Các chức năng được áp dụng một cách lười biếng, được gọi khi cần thiết. Điều này là cần thiết để danh sách được trả về là một khung nhìn, nhưng điều đó có nghĩa là hàm này sẽ được áp dụng nhiều lần cho các hoạt động hàng loạt như List.contains (java.lang.Object) và List.hashCode (). Để điều này thực hiện tốt, chức năng nên được nhanh chóng. Để tránh đánh giá lười biếng khi danh sách trả về không cần phải là chế độ xem, hãy sao chép danh sách được trả về vào danh sách mới bạn chọn.

Ngoài ra trong tài liệu của Collections2.transform()họ đề cập đến việc bạn có được chế độ xem trực tiếp, sự thay đổi đó trong danh sách nguồn ảnh hưởng đến danh sách được chuyển đổi. Loại hành vi này có thể dẫn đến các vấn đề khó theo dõi nếu nhà phát triển không nhận ra cách thức hoạt động.

Nếu bạn muốn có một "bản đồ" cổ điển hơn, nó sẽ chỉ chạy một lần và một lần duy nhất, thì bạn FluentIterablecũng nên sử dụng Guava, một hoạt động đơn giản hơn nhiều. Dưới đây là ví dụ google cho nó:

FluentIterable
       .from(database.getClientList())
       .filter(activeInLastMonth())
       .transform(Functions.toStringFunction())
       .limit(10)
       .toList();

transform()đây là phương pháp bản đồ. Nó sử dụng cùng chức năng <> "gọi lại" như Collections.transform(). Danh sách bạn nhận được là chỉ đọc, sử dụng copyInto()để có được danh sách đọc-ghi.

Nếu không thì tất nhiên khi java8 ra mắt với lambdas, điều này sẽ lỗi thời.



2

Mặc dù đó là một câu hỏi cũ tôi muốn đưa ra một giải pháp khác:

Chỉ cần xác định hoạt động của riêng bạn bằng cách sử dụng java generic và java 8 stream:

public static <S, T> List<T> map(Collection<S> collection, Function<S, T> mapFunction) {
   return collection.stream().map(mapFunction).collect(Collectors.toList());
}

Hơn bạn có thể viết mã như thế này:

List<String> hex = map(Arrays.asList(10, 20, 30, 40, 50), Integer::toHexString);
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.