Operating with a dds library on i386, trying to pull samples repeatedly. I am explicitly 'reading' not 'takeing' the sample, so they should never expire or be removed.
Start two blackboard applications, (1) and (2)
Perform a read in both applications. This will return "Cache is empty".
Write from (1), sensor id: 1, event id: 1, value: 1.
Read from (1), confirm values
Read from (2), confirm values
Write from (2), sensor id: 1, event id: 1, value: 2.
Read from (2), "cache is empty"
Read from (1), "cache is empty"
It seems like I "broke" it! I believe the lifetime for samples should be inifinity (or so I have come to understand... but cannot confirm!) -- but I can't set it explicitly. topicQos.lifespan.duration is of the type Duration_t, but I cannot set it to a "new Duration_t(Duration_t.DURATION_INFINITY_SEC,Duration_t.DURATION_INFINITY_NSEC)" because it is already finalized?
public class Main {
private static final String EVENT_TOPIC_NAME = "EVENTS";
private static BufferedReader in = null;
private static PrintStream out = null;
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
in = new BufferedReader(new InputStreamReader(System.in));
out = new PrintStream(new BufferedOutputStream(System.out));
DomainParticipantFactory factory = DomainParticipantFactory.TheParticipantFactory;
DomainParticipant participant = factory.create_participant(100,
DomainParticipantFactory.PARTICIPANT_QOS_DEFAULT,
null,
StatusKind.STATUS_MASK_NONE);
EventTypeSupport.register_type(participant, EventTypeSupport.get_type_name());
TopicQos topicQos = new TopicQos();
topicQos.durability.direct_communication = true;
topicQos.durability.kind = DurabilityQosPolicyKind.TRANSIENT_DURABILITY_QOS;
topicQos.reliability.kind = ReliabilityQosPolicyKind.RELIABLE_RELIABILITY_QOS;
topicQos.resource_limits.max_instances = 100;
topicQos.resource_limits.max_samples = 100;
topicQos.resource_limits.max_samples_per_instance = 1;
topicQos.ownership.kind = OwnershipQosPolicyKind.SHARED_OWNERSHIP_QOS;
topicQos.history.kind = HistoryQosPolicyKind.KEEP_LAST_HISTORY_QOS;
topicQos.history.depth = 1;
topicQos.history.refilter = RefilterQosPolicyKind.ALL_REFILTER_QOS;
// Since this is on the same computer, and being typed by a human, we can exepct source timestamps to be useful in ordering
topicQos.destination_order.kind = DestinationOrderQosPolicyKind.BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS;
Topic topic =
participant.create_topic(EVENT_TOPIC_NAME,
EventTypeSupport.get_type_name(),
topicQos,
new EventTopicListener(),
StatusKind.STATUS_MASK_ALL);
exitIfNullBecause(topic, "Could not create topic");
Subscriber subscriber = participant.create_subscriber(DomainParticipant.SUBSCRIBER_QOS_DEFAULT,
null,
StatusKind.STATUS_MASK_NONE);
exitIfNullBecause(subscriber, "Could not create subscriber");
DataReader reader = subscriber.create_datareader(participant.lookup_topicdescription(EVENT_TOPIC_NAME),
subscriber.DATAREADER_QOS_USE_TOPIC_QOS,
null,
StatusKind.STATUS_MASK_NONE);
exitIfNullBecause(reader, "Could not create reader");
EventDataReader eventReader = (EventDataReader) reader;
Publisher publisher = participant.create_publisher(DomainParticipant.PUBLISHER_QOS_DEFAULT,
null,
StatusKind.STATUS_MASK_NONE);
exitIfNullBecause(publisher, "Could not create publisher");
DataWriter writer = publisher.create_datawriter(topic,
publisher.DATAWRITER_QOS_USE_TOPIC_QOS,
null,
StatusKind.STATUS_MASK_NONE);
exitIfNullBecause(writer, "Could not create writer");
EventDataWriter eventWriter = (EventDataWriter)writer;
boolean loop = true;
byte inputBuffer[] = new byte[1024];
String command;
while(loop){
print("Enter action [read|write|exit]: ");
command = in.readLine();
if(command.startsWith("r")){
dumpCache(eventReader);
} else if(command.startsWith("w")) {
writeCache(eventWriter);
} else if(command.startsWith("e")){
println("exiting...");
System.exit(0);
} else {
println("Unknown: '" + command + "'");
}
}
System.exit(0);
}
private static void print(String output){
out.print(output);
out.flush();
}
private static void println(String output){
out.println(output);
out.flush();
}
private static void exitIfNullBecause(Object thing, String string) {
if (thing == null) {
println("ERROR: " + string);
System.exit(1);
}
}
private static void dumpCache(EventDataReader eventReader) {
// Something interesting here: I can creat it with a collection as a paramter. TODO: Investigate!
EventSeq eventSeq = new EventSeq();
SampleInfoSeq infoSeq = new SampleInfoSeq();
Event event = null;
SampleInfo info = null;
try{
eventReader.read(eventSeq, infoSeq, 100, SampleStateKind.ANY_SAMPLE_STATE, ViewStateKind.ANY_VIEW_STATE, InstanceStateKind.ANY_INSTANCE_STATE);
} catch (Exception e){
println("Cache is empty");
return;
}
Iterator<SampleInfo> infoIter = infoSeq.iterator();
out.printf("| Sensor ID | Event ID | Value |\n");
for(int i=0; i<infoSeq.size(); i++){
event = (Event)eventSeq.get(i);
out.printf("| %9d | %8d | %5d |\n", event.sensor_id, event.event_id, event.value);
}
out.flush();
}
private static void writeCache(EventDataWriter eventWriter) throws IOException {
Event event = new Event();
print("Sensor ID: ");
String sensor_id_str = in.readLine();
print("Event ID: ");
String event_id_str = in.readLine();
print("Value: ");
String value_str = in.readLine();
Event sample = new Event();
sample.sensor_id = Integer.parseInt(sensor_id_str);
sample.event_id = Integer.parseInt(event_id_str);
sample.value = Integer.parseInt(value_str);
InstanceHandle_t handle = eventWriter.register_instance(sample);
// eventWriter.write(sample, handle);
eventWriter.write_w_timestamp(sample, handle, Time_t.now());
out.printf("SensorID: %s, EventID: %s, Value: %s\n",sensor_id_str,event_id_str,value_str); out.flush();
}
}
The problem does not seem to be related to lifespan.
I'm not sure which DDS implementation you are using but the according to DDS spec, you are performing a zero-copy operation in your dumpCache method. Maybe the implementation that you use behaves like this if you forget to return the loan.
You should normally return_loan after a read/take with zero-copy.
So please add the following code at the end of your dumpCachemethod:
try{
eventReader.return_loan(eventSeq, infoSeq);
} catch (Exception e){
println("Error returning loan");
return;
}
Related
I develop bitcoin protocol using socket, but met some issues. Firstly, when my code connects to bitcoin node, it doesn't give any response. I send version message, but another side node doesn't re-send anything. I think that problem could be that I implement protocol wrong, but I checked and think that it's fine. (2) Secondly, I think that could be impossible connect to bitcoin node using socket, but it's stupid idea. Yea?
One important thing, I coded only socket connection, version sending to bitcoin node, which I found on https://bitnodes.earn.com/nodes/ , and message receiving from node, but it always responses -1.
One more thing, I don't give response from node, but also don't give connection error. (I just say)
Please help me :)
What is wrong that I send version message, but then doesn't give another one from node?
Also, I attach output (connection phases and protocol structure) of console when try to connect to socket.
Connected
f9beb4d976657273696f6e0000000000000000660a75c8397f1101000100000000000000820b905c00000000010000000000000000000000000000000000ffff340e5966208d010000000000000000000000000000000000ffff7f000001208db910e81a17a5dd79102f417572696d61733a302e31362e332f0000000001
Magic:f9beb4d9
Command:76657273696f6e0000000000
Length:00000066
Checksum:0a75c839
Payload:7f1101000100000000000000820b905c00000000010000000000000000000000000000000000ffff340e5966208d010000000000000000000000000000000000ffff7f000001208db910e81a17a5dd79102f417572696d61733a302e31362e332f0000000001
Version:7f110100
Services:0100000000000000
timestamp:820b905c00000000
addr_recv:010000000000000000000000000000000000ffff340e5966208d
addr_from:010000000000000000000000000000000000ffff7f000001208d
nonce:b910e81a17a5dd79
user_agent:102f417572696d61733a302e31362e332f
start_height:00000000
relay:01
Connection end
Main class:
private static String address = "52.14.89.102";
private static int port = 8333;
public static void main(String [] args) throws IOException {
String line = "";
try {
socket = new Socket(address, port);
System.out.println("Connected");
input = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
VersionMessage message = new VersionMessage();
line = Hex.encodeHexString(message.getMessage());
System.out.println(line);
structure(message.getMessage());
out.writeBytes(line);;
} catch(UnknownHostException u) {
System.out.println(u);
} catch (IOException e) {
e.printStackTrace();
}
...
The part of VersionMessage class:
public VersionMessage() {
super();
this.version = 70015;
this.services = 1; // NODE_NETWORK
this.timestamp = System.currentTimeMillis() / 1000;
this.nonce = new Random().nextLong();
this.userAgent = "/Satoshi:0.16.3/";
this.startHeight = 0;
this.relay = true;
contructPayload();
contructMessage();
}
#Override
public void contructPayload() {
addByteArray(dataParser.toInt32(version));
addByteArray(dataParser.toInt64(services));
addByteArray(dataParser.toInt64(timestamp));
addAddr("52.14.89.102", 8333);
addAddr("127.0.0.1", 8333);
addByteArray(dataParser.toInt64(nonce));
addStr(userAgent);
addByteArray(dataParser.toInt32(startHeight));
addByteArray(dataParser.toInt8(relay ? (byte) 1 : (byte) 0));
payload = new byte[payloadBytes.size()];
IntStream.range(0, payloadBytes.size()).forEach(i -> payload[i] = payloadBytes.get(i).byteValue());
}
BitcoinMessage (parent of VersionMessage):
public BitcoinMessage() {
magic = 0xf9beb4d9;;
payloadBytes = new ArrayList<Integer>();
dataParser = new DataParser();
}
public void contructMessage() {
message = new byte[MAGIC_LENGTH + COMMAND_LENGTH + PAYLOAD_LENGTH_SIZE + CHECKSUM_LENGTH + payload.length];
length = payload.length;
byte[] doubleHashedPayload = MessageUtils.doubleHashWithSha256(payload);
MessageUtils.addToByteArray(MessageUtils.intToBytes(magic, MAGIC_LENGTH), 0, MAGIC_LENGTH, message);
MessageUtils.addToByteArray(getCommandName().getBytes(), MAGIC_LENGTH, COMMAND_LENGTH, message);
MessageUtils.addToByteArray(MessageUtils.intToBytes(length, PAYLOAD_LENGTH_SIZE), MAGIC_LENGTH + COMMAND_LENGTH, PAYLOAD_LENGTH_SIZE, message);
MessageUtils.addToByteArray(doubleHashedPayload, MAGIC_LENGTH + COMMAND_LENGTH + PAYLOAD_LENGTH_SIZE, CHECKSUM_LENGTH, message);
MessageUtils.addToByteArray(payload, MAGIC_LENGTH + COMMAND_LENGTH + PAYLOAD_LENGTH_SIZE + CHECKSUM_LENGTH, payload.length, message);
}
I have a function that searches for a list and for each item in the list I have another list. These two lists will have to be transformed into a text file to be imported into a software. The problem I'm having is slow ...
My first list has about 500 records, and every record in that list has another list that can range from 1 record to infinity. This takes about 20 minutes to complete. When I comment the updates (updates the status of each item of the 2 list) the time drops to 9 minutes.
Can someone help me ?
private String getExportacaoApontamento(
String idsExportar,
String dataInicial,
String dataFinal,
String status,
String tipoFiltro,
String filtro,
String turma,
boolean exportarTodos) throws SQLException {
StringBuilder stringBuilder = new StringBuilder();
try (
Connection conMySql = U_Conexao.getConexaoMySQL();
Connection conOracle = U_Conexao.getConexaoOracle()) {
if (conMySql != null) {
List<C_Sequencia> listSequencia;
R_Sequencia r_Sequencia = new R_Sequencia(conMySql, null);
if (status.equals(String.valueOf(C_Status.TODOS))) {
status = C_Status.PENDENTE + ", " + C_Status.EXPORTADO;
}
String orderBy = "S." + C_Sequencia.DATA + ", S." + C_Sequencia.COD_COLETOR + ", S." + C_Sequencia.COD_FISCAL;
if (exportarTodos == false) {
listSequencia = r_Sequencia.listExportarId(idsExportar, dataInicial, dataFinal, orderBy);
} else {
tipoFiltro = verificarFiltroApontamento(tipoFiltro);
if (filtro == null || filtro.isEmpty()) {
listSequencia = r_Sequencia.listExportarData(dataInicial, dataFinal, status, turma, orderBy);
} else {
listSequencia = r_Sequencia.listExportarFiltro(dataInicial, dataFinal, tipoFiltro, filtro, status, turma, orderBy);
}
}
if (!listSequencia.isEmpty()) {
if (!verificarLiberacoes(listSequencia, conMySql, conOracle)) {
return "-1";
}
C_Sequencia seqAntiga = null;
R_Producao r_Producao = new R_Producao(conMySql, conOracle);
for (C_Sequencia sequencia : listSequencia) {
C_Sequencia seqNova = sequencia;
String retornoSequencia = gerarSequencia(seqAntiga, seqNova);
if (!retornoSequencia.isEmpty()) {
stringBuilder.append(retornoSequencia);
}
List<C_Producao> listProducao = r_Producao.getProducaoExportar(sequencia.getChave(), status);
for (C_Producao producao : listProducao) {
DecimalFormat decimal = new DecimalFormat("########.00");
String prod = String.valueOf(decimal.format(Double.parseDouble(producao.getProducao())));
String meta = String.valueOf(decimal.format(Double.parseDouble(producao.getMeta())));
prod = prod.replace(",", "");
meta = meta.replace(",", "");
stringBuilder.append("02;")
.append(String.format("%5d", producao.getCodColetor())).append(";")
.append(U_DataHora.formatarData(producao.getDataHora(), U_DataHora.DDMMYYYY_HHMMSS, U_DataHora.DDMMYYYY)).append(";")
.append(String.format("%10d", producao.getFuncionario().getMatricula())).append(";")
.append(String.format("%9d", sequencia.getCodCc())).append(";")
.append(String.format("%4d", sequencia.getCodOp())).append(";")
.append(String.format("%4d", sequencia.getCodOp())).append(";")
.append(" ;")
.append(String.format("%6d", Long.parseLong(sequencia.getCodFazenda()))).append(";")
.append(String.format("%6d", Long.parseLong(sequencia.getCodTalhao()))).append(";")
.append(String.format("%10s", prod)).append(";")
.append(" 0000000;")
.append(";")
.append(" ;")
.append(String.format("%9s", meta)).append(";")
.append(String.format("%4d", sequencia.getCodSequencia())).append(";")
.append(" ;")
.append(" ;")
.append(" ;")
.append(" ;")
.append(" ;")
.append(" ;")
.append(String.format("%9d", sequencia.getCodOs())).append(";")
.append("\r\n");
if (producao.getStatus().getStatus() != C_Status.EXPORTADO) {
r_Producao.atualizarStatus(producao.getChave(), C_Status.EXPORTADO); // Atualiza status para exportado
}
}
// Atualiza o status de todas as produções da sequencia da posição atual
//r_Producao.atualizaStatusProducoesPorChaveSequencia(sequencia.getChave(), C_Status.EXPORTADO);
seqAntiga = seqNova;
if (sequencia.getStatus().getStatus() != C_Status.EXPORTADO) {
r_Sequencia.atualizarStatus(sequencia.getChave(), C_Status.EXPORTADO); // Atualiza status para exportado
}
}
}
}
} catch (Exception e) {
U_Log.erro(TAG, e.toString());
return e.toString();
}
return stringBuilder.toString();
}
private String gerarSequencia(C_Sequencia seqAntiga, C_Sequencia seqNova) {
StringBuilder sequenciaBuilder = new StringBuilder();
String texto = sequenciaBuilder.append("01;")
.append(String.format("%5d", seqNova.getCodColetor())).append(";")
.append(U_DataHora.formatarData(seqNova.getData(), U_DataHora.DDMMYYYY_HHMMSS, U_DataHora.DDMMYYYY)).append(";")
.append(String.format("%10d", seqNova.getCodFiscal())).append(";")
.append(String.format("%10d", seqNova.getCodFiscal())).append(";")
.append("\r\n").toString();
if (seqAntiga != null) {
if (!seqAntiga.getData().equals(seqNova.getData())
|| !Objects.equals(seqAntiga.getCodColetor(), seqNova.getCodColetor())
|| !Objects.equals(seqAntiga.getCodFiscal(), seqNova.getCodFiscal())) {
return texto;
} else {
return "";
}
} else {
return texto;
}
}
Result here
Here i commented update in the DB
for (C_Sequencia sequencia : listSequencia) {
...
for (C_Producao producao : listProducao) {
...
// update status in DB
if (producao.getStatus().getStatus() != C_Status.EXPORTADO) {
r_Producao.atualizarStatus(producao.getChave(), C_Status.EXPORTADO);
}
}
// update status in DB
if (sequencia.getStatus().getStatus() != C_Status.EXPORTADO) {
r_Sequencia.atualizarStatus(sequencia.getChave(), C_Status.EXPORTADO);
}
}
Result: Total time 9 minutes
Now, i commented the part that I built string
for (C_Sequencia sequencia : listSequencia) {
...
// here build a part of the string in method " gerarSequencia "
// i commented a part inside method " gerarSequencia "
String retornoSequencia = gerarSequencia(seqAntiga, seqNova);
...
for (C_Producao producao : listProducao) {
...
// Here i commented another part of the string
...
}
}
Result: Total time is 14 minutes -
Practically running only the updates lines
i solved my problem. I've changed logic. The actual problem was doing many SELECT in the database and this was making it extremely slow. Now is a single SELECT. The total time is now 6 seconds.
You have 2 problems:
1 - you are actually not doing the write to the file, but returning some big String. I don't think processing such large lists in memory is good idea.
2 - How are you doing the update? I guess the problem is that you are hitting db every row. You should think how to do it at once.
private File writeRecords(String filenaam, List<String> records) throws IOException
{
File file = new File(filenaam);
try (FileOutputStream fos = new FileOutputStream(file);
PrintWriter writer = new PrintWriter(fos))
{
records.forEach(rec -> writer.println(rec));
writer.flush();
}
return file;
}
And if you want to compress the file:
private void compressFiles(String zipfile, List<File> files) throws IOException
{
try (FileOutputStream fos = new FileOutputStream(zipfile);
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos)))
{
for (File file : files)
{
ZipEntry entry = new ZipEntry(file.getName());
byte[] bytes = Files.readAllBytes(Paths.get(file.getAbsolutePath()));
zos.putNextEntry(entry);
zos.write(bytes, 0, bytes.length);
zos.closeEntry();
}
zos.finish();
zos.flush();
}
}
This link may helpful for your performance issue,
this may be not file writing problem but as far as I believe the issue is String manipulation problem.
What's the fastest way to concatenate two Strings in Java?
I am using this codes in communicating with Evolis KC200 printer:
#Test
public void studyPipe() {
try {
String echoText = " {\"id\":\"1\",\"jsonrpc\":\"2.0\",\"method\":\"CMD.GetStatus\",\"params\":{\"device\":\"Evolis KC200\"}}";
System.out.println("CMD.GetStatus Request: " + echoText);
String pipeName = "\\\\.\\pipe\\EspfServer00";
RandomAccessFile pipe = new RandomAccessFile(pipeName, "rw");
System.out.println("Writing in pipe: " + echoText + " in pipe "
+ pipeName);
pipe.write(echoText.getBytes("UTF-8"));
// Thread.sleep(1000);
String echoResponse = pipe.readLine();
System.out.println("Response: " + echoResponse);
pipe.close();
} catch (Exception e) {
e.printStackTrace();
}
}
But all I'm getting is this:
java.io.IOException: No process is on the other end of the pipe
at java.io.RandomAccessFile.read0(Native Method)
at java.io.RandomAccessFile.read(RandomAccessFile.java:330)
at java.io.RandomAccessFile.readLine(RandomAccessFile.java:939)
at
They have a test tool built on another language (C#) and their Named Pipe client looks like this:
What is missing in my JAVA codes?
public static string SendRequestPipe(string ip, string port, string request)
{
NamedPipeClientStream objPipeClient;
string answer = string.Empty;
objPipeClient = new NamedPipeClientStream(ip, port, PipeDirection.InOut);
try
{
// Connexion au named pipe ou attente de la disponibilité du named pipe
objPipeClient.Connect(1000);
// Paramétrage de la connexion
objPipeClient.ReadMode = PipeTransmissionMode.Message;
if (objPipeClient.IsConnected == true)
{
// Send request
byte[] datain = Encoding.UTF8.GetBytes(request);
objPipeClient.Write(datain, 0, datain.Length);
// Get answer
int recv = 0;
byte[] data = new byte[1024];
do
{
recv = objPipeClient.Read(data, 0, data.Length);
answer += Encoding.UTF8.GetString(data, 0, recv);
} while (!objPipeClient.IsMessageComplete);
}
}
catch (Exception ex)
{
}
finally
{
objPipeClient.Close();
objPipeClient.Dispose();
}
return answer;
}
I also tried similar approaches in Java but I'm getting the same error.
UPDATE:
I think I know the issue already but I still do not have the resolution.
It seems that the JAVA code is creating another instance of the PIPE that is why it is not receiving any process on that new instance.
I tested with the C# code and it was not creating a new instance.
I checked the instances using this tool:
https://learn.microsoft.com/en-us/sysinternals/downloads/pipelist
So I'm trying to import a CSV file into my MySQL database through my Java program. The program imports everything that's in the file, like it's suppose to, but the first row, it send to the end of the table, and the program see it's there, but if I search for that nr, it says it doesn't exists. And if I go directly to the database table and edit the nr(if the nr is 137, and I edit and write 137 again) the program recognize that nr, and if I search for it, it will find, and the database table organizes itself and sends that entry where is suppose to be.
I just don't see any logic in this. I someone could help me out, I'd appreciated.
LOAD DATA INFILE 'C:\\Users\\carla.DESKTOP-9364K9K\\Desktop\\Alunos_1.csv'
INTO TABLE utentes character set utf8
FIELDS TERMINATED BY ','
(NrProcesso, Nome, #Nome_Resumido, Ano, Turma, #Subsidio, #Nome_EE, #NIF, #email, #Obs)
SET
Subsidio = IF(#Subsidio='','Nenhum',#Subsidio),
Nome_Resumido = IF(#Nome_Resumido='',NULL,#Nome_Resumido),
Nome_EE = IF(#Nome_EE='',NULL,#Nome_EE),
NIF = IF(#NIF = '', NULL,#NIF),
email = IF(#email='',NULL,#email),
Obs = IF(#Obs='',NULL,#Obs);
Thanks in advance.
You have do do something to check cell/column value and form a sql to inject in MySQL.
public List<Object> getRecordingsListFromCsv(String csvFileLocation, String mp3FileLocation, String mp3FileLocation2, String saveFileLocation, ChannelSftp sftp) {
Map<String, File> recordingsFilesMap = null;
BufferedReader br = null;
List<String> errorFilesList = new ArrayList<>();
List<Object> tempList = new LinkedList<>();
try {
csvRows = 0;
recordingsFilesMap = new LinkedHashMap<>();
br = new BufferedReader(new FileReader(csvFileLocation));
String line = br.readLine();
scriptLog.info("\n" + csvFileLocation + " loaded. Parsing File...");
while ((line = br.readLine()) != null) {
String[] csvArray = parseCsvLineToArray(line);
// System.out.println(Arrays.asList(csvArray) + "\n\n");
if (csvArray[0].trim().isEmpty()) {
continue;
}
/* Do your stuff here */
csvRows++;
}
} catch (FileNotFoundException e) {
scriptLog.error("\n---ERROR---\n FILE NOT FOUND: " + csvFileLocation);
String errorStr = "Type=" + e.toString();
errorStr += "StackTrace=" + Arrays.toString(e.getStackTrace());
scriptLog.error(errorStr);
} catch (IOException e) {
String errorStr = "Type=" + e.toString();
errorStr += "StackTrace=" + Arrays.toString(e.getStackTrace());
scriptLog.error(errorStr);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
System.out.println(e.toString());
}
}
}
Hope it will help you at some extent!!
I am trying to learn how to utilize Java 8 features(such as lambdas and streams) in my daily programming, since it makes for much cleaner code.
Here's what I am currently working on:
I get a string stream from a local file with some data which I turn into objects later. The input file structure looks something like this:
Airport name; Country; Continent; some number;
And my code looks like this:
public class AirportConsumer implements AirportAPI {
List<Airport> airports = new ArrayList<Airport>();
#Override
public Stream<Airport> getAirports() {
Stream<String> stream = null;
try {
stream = Files.lines(Paths.get("resources/planes.txt"));
stream.forEach(line -> createAirport(line));
} catch (IOException e) {
e.printStackTrace();
}
return airports.stream();
}
public void createAirport(String line) {
String airport, country, continent;
int length;
airport = line.substring(0, line.indexOf(';')).trim();
line = line.replace(airport + ";", "");
country = line.substring(0,line.indexOf(';')).trim();
line = line.replace(country + ";", "");
continent = line.substring(0,line.indexOf(';')).trim();
line = line.replace(continent + ";", "");
length = Integer.parseInt(line.substring(0,line.indexOf(';')).trim());
airports.add(new Airport(airport, country, continent, length));
}
}
And in my main class I iterate over the object stream and print out the results:
public class Main {
public void toString(Airport t){
System.out.println(t.getName() + " " + t.getContinent());
}
public static void main(String[] args) throws IOException {
Main m = new Main();
m.whatever();
}
private void whatever() throws IOException {
AirportAPI k = new AirportConsumer();
Stream<Airport> s;
s = k.getAirports();
s.forEach(this::toString);
}
}
My question is this: How can I optimize this code, so I don't have to parse the lines from the file separately, but instead create a stream of objects Airport straight from the source file? Or is this the extent in which I can do this?
You need to use map() to transform the data as it comes past.
Files.lines(Paths.get("resources/planes.txt"))
.map(line -> createAirport(line));
This will return a Stream<Airport> - if you want to return a List, then you'll need to use the collect method at the end.
This approach is also stateless, which means you won't need the instance-level airports value.
You'll need to update your createAirport method to return something:
public Airport createAirport(String line) {
String airport = line.substring(0, line.indexOf(';')).trim();
line = line.replace(airport + ";", "");
String country = line.substring(0,line.indexOf(';')).trim();
line = line.replace(country + ";", "");
String continent = line.substring(0,line.indexOf(';')).trim();
line = line.replace(continent + ";", "");
int length = Integer.parseInt(line.substring(0,line.indexOf(';')).trim());
return new Airport(airport, country, continent, length);
}
If you're looking for a more functional approach to your code, you may want to consider a rewrite of createAirport so it doesn't mutate line. Builders are also nice for this kind of thing.
public Airport createAirport(final String line) {
final String[] fields = line.split(";");
return new Airport(fields[0].trim(),
fields[1].trim(),
fields[2].trim(),
Integer.parseInt(fields[3].trim()));
}
Throwing it all together, your class now looks like this.
public class AirportConsumer implements AirportAPI {
#Override
public Stream<Airport> getAirports() {
Stream<String> stream = null;
try {
stream = Files.lines(Paths.get("resources/planes.txt"))
.map(line -> createAirport(line));
} catch (IOException e) {
stream = Stream.empty();
e.printStackTrace();
}
return stream;
}
private Airport createAirport(final String line) {
final String[] fields = line.split(";");
return new Airport(fields[0].trim(),
fields[1].trim(),
fields[2].trim(),
Integer.parseInt(fields[3].trim()));
}
}
The code posted by Steve looks great. But there are still two places can be improved:
1, How to split a string.
2, It may cause issue if the people forget or don't know to close the stream created by calling getAirports() method. So it's better to finish the task(toList() or whatever) in place.
Here is code by abacus-common
try(Reader reader = IOUtil.createBufferedReader(file)) {
List<Airport> airportList = Stream.of(reader).map(line -> {
String[] strs = Splitter.with(";").trim(true).splitToArray(line);
return Airport(strs[0], strs[1], strs[2], Integer.valueOf(strs[3]));
}).toList();
} catch (IOException e) {
throw new RuntimeException(e);
}
// Or By the Try:
List<Airport> airportList = Try.stream(file).call(s -> s.map(line -> {
String[] strs = Splitter.with(";").trim(true).splitToArray(line);
return Airport(strs[0], strs[1], strs[2], Integer.valueOf(strs[3]));
}).toList())
Disclosure: I'm the developer of abacus-common.