Я создал этот класс для того неизменны и имеющий свободно API:Будет ли JIT оптимизировать новые объекты
public final class Message {
public final String email;
public final String escalationEmail;
public final String assignee;
public final String conversationId;
public final String subject;
public final String userId;
public Message(String email, String escalationEmail, String assignee, String conversationId, String subject, String userId) {
this.email = email;
this.escalationEmail = escalationEmail;
this.assignee = assignee;
this.conversationId = conversationId;
this.subject = subject;
this.userId = userId;
}
public Message() {
email = "";
escalationEmail = "";
assignee = "";
conversationId = "";
subject = "";
userId = "";
}
public Message email(String e) { return new Message(e, escalationEmail, assignee, conversationId, subject, userId); }
public Message escalationEmail(String e) { return new Message(email, e, assignee, conversationId, subject, userId); }
public Message assignee(String a) { return new Message(email, escalationEmail, a, conversationId, subject, userId); }
public Message conversationId(String c) { return new Message(email, escalationEmail, assignee, c, subject, userId); }
public Message subject(String s) { return new Message(email, escalationEmail, assignee, conversationId, s, userId); }
public Message userId(String u) { return new Message(email, escalationEmail, assignee, conversationId, subject, u); }
}
Мой вопрос, будет ли оптимизатор сможет избежать многих объектов творений, когда создается новый объект например:
Message m = new Message()
.email("[email protected]")
.assignee("[email protected]")
.subject("subj");
Есть ли что-нибудь, что можно получить от создания отдельного объекта изменяемого объекта-строителя?
Обновление 2: После прочтения ответа apangin мой критерий признан недействительным. Я буду держать его здесь для справки о том, как не для сравнения :)
Update: я взял на себя смелость измерения это сам с этим кодом:
public final class Message {
public final String email;
public final String escalationEmail;
public final String assignee;
public final String conversationId;
public final String subject;
public final String userId;
public static final class MessageBuilder {
private String email;
private String escalationEmail;
private String assignee;
private String conversationId;
private String subject;
private String userId;
MessageBuilder email(String e) { email = e; return this; }
MessageBuilder escalationEmail(String e) { escalationEmail = e; return this; }
MessageBuilder assignee(String e) { assignee = e; return this; }
MessageBuilder conversationId(String e) { conversationId = e; return this; }
MessageBuilder subject(String e) { subject = e; return this; }
MessageBuilder userId(String e) { userId = e; return this; }
public Message create() {
return new Message(email, escalationEmail, assignee, conversationId, subject, userId);
}
}
public static MessageBuilder createNew() {
return new MessageBuilder();
}
public Message(String email, String escalationEmail, String assignee, String conversationId, String subject, String userId) {
this.email = email;
this.escalationEmail = escalationEmail;
this.assignee = assignee;
this.conversationId = conversationId;
this.subject = subject;
this.userId = userId;
}
public Message() {
email = "";
escalationEmail = "";
assignee = "";
conversationId = "";
subject = "";
userId = "";
}
public Message email(String e) { return new Message(e, escalationEmail, assignee, conversationId, subject, userId); }
public Message escalationEmail(String e) { return new Message(email, e, assignee, conversationId, subject, userId); }
public Message assignee(String a) { return new Message(email, escalationEmail, a, conversationId, subject, userId); }
public Message conversationId(String c) { return new Message(email, escalationEmail, assignee, c, subject, userId); }
public Message subject(String s) { return new Message(email, escalationEmail, assignee, conversationId, s, userId); }
public Message userId(String u) { return new Message(email, escalationEmail, assignee, conversationId, subject, u); }
static String getString() {
return new String("hello");
// return "hello";
}
public static void main(String[] args) {
int n = 1000000000;
long before1 = System.nanoTime();
for (int i = 0; i < n; ++i) {
Message m = new Message()
.email(getString())
.assignee(getString())
.conversationId(getString())
.escalationEmail(getString())
.subject(getString())
.userId(getString());
}
long after1 = System.nanoTime();
long before2 = System.nanoTime();
for (int i = 0; i < n; ++i) {
Message m = Message.createNew()
.email(getString())
.assignee(getString())
.conversationId(getString())
.escalationEmail(getString())
.subject(getString())
.userId(getString())
.create();
}
long after2 = System.nanoTime();
System.out.println("no builder : " + (after1 - before1)/1000000000.0);
System.out.println("with builder: " + (after2 - before2)/1000000000.0);
}
}
я нашел разницу быть значительным (строитель быстрее), если строковые аргументы не являются новыми объектами, но все равно (см. комментарий в getString)
В том, что я себе представляю, более реалистичный сценарий, когда все строки являются новыми объектами, разница пренебрежимо мало, и запуск JVM приведет к тому, что первый быть немного медленнее (я пробовал в обоих направлениях).
С «новой строкой» код был в целом много раз медленнее (мне пришлось уменьшить n
), возможно, указывая на то, что происходит некоторая оптимизация «нового сообщения», но не от " новая строка ".
Вы также можете получить от строителя, чтобы избежать необходимости переписывать методы N при добавлении (N + 1) -го поля к вашему классу. – khelwood
Вот почему шаблон строителя не делает это так ... в конце концов, вы создаете много новых объектов; поэтому, если этот код работает «часто»; он будет постоянно создавать «мусор». – GhostCat
@GhostCat Это моя забота, но возможно, что jit может оптимизировать это. Если так, я предпочитаю этот путь. – morten