2011-08-15 43 views
17

Câu hỏi này là để đáp lại một câu hỏi khác bởi opensas: building a generic initializer function in javakiểu dữ liệu Generic phương pháp chuyển đổi

Từ câu hỏi của anh nó trở nên rõ ràng rằng ông cần phải chuyển đổi từ bất kỳ loại dữ liệu T1 đến một loại T2. Khi tôi nói "kiểu dữ liệu" ở đây, tôi có nghĩa là các loại giới hạn đối với những loại thường được sử dụng để đại diện cho dữ liệu thô: Integer, String, Date, v.v ... Vì mục đích của câu hỏi này, chúng tôi có thể xem xét nguyên thủy để được đóng hộp.

Tôi tự hỏi liệu có API nào hỗ trợ chuyển đổi giữa các loại trong đó cả đầu vào và đầu ra được tổng quát thành một tập hợp các loại dữ liệu được hỗ trợ. Tôi đã có một cái nhìn tại Apache Commons' beanutils.converters package, nhưng có một lớp chuyển đổi riêng biệt cho mỗi đầu vào được biết đến. Tôi đang tìm bất kỳ chức năng mà thực hiện một cái gì đó giống như chữ ký sau đây:

static <IN, OUT> OUT convert(IN value, Class<OUT> targetType); 

hoặc khác

static <IN, OUT> OUT convert(IN value, OUT defaultValue); 

Nó thực sự sẽ không quá khó để thực hiện các loại lập bản đồ chính mình, hoặc sử dụng một bó của các khối else if trỏ đến các Trình chuyển đổi Commons khác nhau hoặc một số khác là Map<Class<?>, Converter> cho cùng một mục đích. Nhưng tôi tự hỏi liệu loại chức năng này có được hỗ trợ ở đâu đó không.

Ngoài ra, nếu điều này xảy ra, tôi xin lỗi. Tôi đã thử tìm những câu hỏi tương tự và đã rất ngạc nhiên khi tôi thấy không phù hợp với tình huống này.

EDIT: nên một ví dụ về mã này trong hành động sẽ là:

Integer i = GenericConverter.convert("123", Integer.class); //returns 123 
Date d = GenericConverter.convert(1313381772316L, Date.class); //returns today's date 
Boolean b = GenericConverter.convert(0, Boolean.class);  //returns false 
Long l = GenericConverter.convert("asdf", Long.class);   //RuntimeException 

UPDATE: Các BalusC mã tôi liên kết thác gần với nhãn hiệu, và câu trả lời Bohemian là một giải pháp tốt đẹp nhẹ (mặc dù nó không hoạt động đối với các chuyển đổi Boolean). Anh ấy cũng đúng rằng ngày tháng có thể được xử lý riêng nếu chúng tôi muốn tổng quát hóa việc chuyển đổi các loại dữ liệu khác. Tôi vẫn hy vọng cho câu trả lời bổ sung mặc dù - đặc biệt là nếu có nhiều hơn một API tay-off có sẵn ở đâu đó.

+0

Bạn có thể hiển thị mã này đang hoạt động không? Không thể nói rằng tôi thực sự có thể hiểu mục tiêu của bạn là gì. –

+0

@ Maurício - đã thêm một số ví dụ –

Trả lời

11

Trong JDK 8 điều này có thể dễ dàng được triển khai với giao diện java.util.functions.Mapper mới và lambda expression.

Mapper<String,Integer> atoi = s -> Integer.valueOf(s); 
Integer r = atoi.map("10"); 

Sử dụng tài liệu tham khảo phương pháp nó có thể thậm chí đơn giản hơn:

Mapper<String, Integer> atoi = Integer::new; 
Integer r = atoi.map("10"); 

Hoặc những thứ như:

List<Long> dates = asList(1344754620310L,1344754854877L); 
List<Date> asDates = dates.map(Date::new).into(new ArrayList<Date>()); 

Hoặc mát chuyển đổi như:

List<Integer> myInts = "5,4,3,2,1,0,6,7,8,9" 
    .splitAsStream(",") 
    .map(Integer::new) 
    .into(new ArrayList<Integer>()); 

Trong việc thực hiện hiện tại của API JDK8, af ew người lập bản đồ mặc định đã được xác định (tức là LongMapper, IntMapper, DoubleMapper) và có một lớp tiện ích gọi là Mappers định nghĩa một số người khác như một ánh xạ chuỗi, và mapper sắc, một mapper liên tục vv

Tôi không chắc chắn nếu điều này là những gì bạn đang theo đuổi, nhưng chắc chắn nó phải là một cách hay để thực hiện nó.

Các trường hợp giống như bạn đề nghị cho:

static <IN, OUT> OUT convert(IN value, Class<OUT> targetType); 

có thể được thực hiện với lớp Mappers tiện ích:

Mapper<String, Integer> atoi = Mappers.instantiate(String.class, Integer.class); 
Integer r = atoi.map("10"); 

Và chữ ký của bạn:

static <IN, OUT> OUT convert(IN value, OUT default); 

thể được thực hiện với một cái gì đó như:

Mapper<String, Integer> atoi = chain(substitute(null, "0"), Integer::new); 
Integer r = atoi.map(null); //produces 0 

Như vậy, một mã như thế này ...

List<String> data = asList("0", null, "2", null, "4", null, "6"); 
List<Integer> myInts = data.map(chain(substitute(null, "0"), Integer::new)).into(new ArrayList<Integer>()); 
System.out.println(myInts); 

sẽ mang lại: [0, 0, 2, 0, 4, 0, 6]

+1

+1 Câu trả lời hay - Tôi nghĩ tôi sẽ chấp nhận Dominic cho đến khi có sẵn JDK 8. –

+5

Bây giờ là năm 2016 và không có 'java.util.functions.Mapper' nhưng có' java.util.function.Function' – Alex

1

tôi tìm thấy một cái gì đó bởi BalusC trông gần với những gì tôi yêu cầu cho: http://balusc.blogspot.com/2007/08/generic-object-converter.html

Đáng tiếc là không có gì liên quan đến ngày chuyển đổi được hỗ trợ, nhưng như các ý kiến ​​cho thấy, phương pháp chuyển đổi hơn có thể dễ dàng thêm. Lớp của ông về cơ bản là một khuôn khổ nhỏ đẹp sử dụng sự phản chiếu để thu thập tất cả các phương thức chuyển đổi khi chạy và đặt chúng trong một HashMap<String, Method> trong đó khóa String là một id duy nhất cho kết hợp đầu vào-đầu ra đó.

Vẫn đang tìm kiếm các đề xuất khác! Riêng với một API có nhiều tay hơn mã này tôi liên kết đến.

18

Tôi không biết bất kỳ thư viện nào, tuy nhiên mã chỉ là một dòng.

Ngoài ngày, tất cả nguyên thủy đóng hộp có một chuỗi construtor, vì vậy phương pháp này hiện các trick:

public static <I, O> O convert(I input, Class<O> outputClass) throws Exception { 
    return input == null ? null : outputClass.getConstructor(String.class).newInstance(input.toString()); 
} 

Để phục vụ cho những ngày, bạn thể sử dụng instanceof trong phương pháp này, nhưng tôi muốn giới thiệu một phương pháp riêng biệt, kể từ ngày chuyển đổi là một định dạng và bối cảnh nhạy cảm điều (ví dụ như String -> Ngày phân tích và sử dụng định dạng ?, Long -> Ngày đặt thời gian).

Tôi đã cố tình để lại lỗi/xử lý đặc biệt cho người đọc dưới dạng tập thể dục.

+1

+1 thật thú vị, không nhận ra tất cả các nguyên thủy đóng hộp có các hàm tạo 'String'. Một số chuyển đổi không được hỗ trợ, chẳng hạn như 'Boolean' =>' Integer', nhưng sau đó lại là trường hợp góc. Và khi bạn chỉ ra điều này không tính đến Ngày tháng (hoặc các kiểu dữ liệu khác do người dùng xác định ") –

+3

Ngoài ra:" Tôi đã cố tình để lại lỗi/xử lý đặc biệt cho người đọc như một bài tập. " Tôi biết bạn chỉ muốn có được nó trên một dòng :) –

+0

loại 'I' là không cần thiết ở đây; nó chỉ có thể là 'Object' – user102008

2

Hãy xem Variance, cho phép bạn thiết lập ngữ cảnh chuyển đổi loại với nhiều người chuyển đổi khác nhau đã đăng ký và sau đó di chuyển các giá trị vào và ra khỏi loại Biến thể với chuyển đổi loại được xử lý theo ngữ cảnh.

Variant aVariant = Variant.of("1.2345"); 
double aDouble = aVariant.doubleValue(); 

int anInt = Variant.of("12").intValue(); 
String aString = Variant.of(12.0).toString(); 
Date aDate = Variant.of("2012-04-06").as(Date.class); 
String anIsoFormattedDate = Variant.of(aDate).in(isoDateFormattingContext).toString() 

chuyển đổi chỉ là GuavaFunctions từ loại này sang loại khác, và bạn có thể đăng ký riêng của bạn, trọng chuyển đổi hiện nơi mong muốn.

+0

+1 Rất tuyệt vời - cảm ơn bạn đã chia sẻ. –

1

Nếu bạn đang sử dụng Spring Framework (mùa xuân-core), bạn có thể sử dụng lớp

org.springframework.core.convert.support.DefaultConversionService 

Mặc định constructor thêm nhiều loại chuyển đổi và bạn có thể thêm riêng của bạn bằng cách thực hiện giao diện Converter và gọi addConverter (Converter). Ngoài ra còn có tốt đẹp unit test hiển thị một số kết hợp chuyển đổi.

Các vấn đề liên quan