My SimpleDateFormat keeps throwing a ParseException. I can’t get it to actually get into the try block, it just keeps going directly to my catch. Any idea what is wrong in my code?
public static String getEventDate() throws ParseException {
System.out.println("When is the date of your event? (dd/MM/yyyy)");
String date = in.nextLine();
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date eventDate = null;
try {
eventDate = dateFormat.parse(date);
} catch (ParseException e) {
System.out.println("Error in date format");
}
String finalDate = dateFormat.format(eventDate);
return finalDate;
}
public static void main(String[] args) throws ParseException {
Event event = getEventInfo();
System.out.println(event);
}
public static Event getEventInfo() throws ParseException {
String eventType = getEventType();
String eventDate = getEventDate();
Event event = new Event(eventType, eventDate);
return event;
}
Related
I want to return a String from a callback
My class which fetch date from server in a thread and i want this value in main thread as a String. I am beginner in Java.
public class InternetDate {
private final Activity activity;
private String finalDate = "";
public InternetDate(Activity activity) {
this.activity = activity;
}
public void setDateAndTimeFormat(String dateAndTimeFormat) {
mDateAndTimeFormat = dateAndTimeFormat;
}
public void getCurrentDate(OnGetDate onGetDate) {
new BackgroundTask(activity) {
#Override
public void doInBackground() {
try {
finalDate = getCurrentDateFromInternet();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
#Override
public void onPostExecute() {
try {
JSONObject jb = new JSONObject(finalDate);
String name = jb.getString("UnixTimeStamp");
onGetDate.onSuccess(name);
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
} catch (JSONException e) {
}
}
}.execute();
}
private String getCurrentDateFromInternet() throws Exception {
String date_api = example.com/api;
URL url = new URL(date_api);
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(url.openStream()));
return in.readLine();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
}
}
public interface OnGetDate {
void onSuccess(String date);
}
I want this as a String. Please help me to archive this String in MainThread
private String getDate(){
String currentDate = "";
InternetDate internetDate = new InternetDate(this);
internetDate.getCurrentDate(new InternetDate.OnGetDate() {
#Override
public void onSuccess(String date) {
currentDate = date; // Null return
}
});
return currentDate;
}
You might wait for the response using a semaphore, but this kind of code is blocking by nature and leads to apps with a poor user experience, because the ui thread is blocked during the whole process
//import java.util.concurrent.*;
//[...]
private String getDate() throws TimeoutException {
final String[] result = new String[]{null};
final Semaphore sem = new Semaphore(0);
new InternetDate(this).getCurrentDate(new InternetDate.OnGetDate() {
#Override
public void onSuccess(String date) {
result[0] = date; // Null return
sem.release();
}
});
try {
if (sem.tryAcquire(10, TimeUnit.SECONDS)) {
return result[0];
} else {
throw new TimeoutException("no response after 10 seconds");
}
} catch(InterruptedException e) {
return null;
}
}
You can use Executors :
private String getDate() throws ExecutionException, InterruptedException {
// This line is non-blocking:
Future<String> future = Executors.newCachedThreadPool()
.submit(() -> new InternetDate().getCurrentDateFromInternet());
// The invocation of 'get' is blocking:
return future.get();
}
I assume getCurrentDateFromInternet returns the date in the format you want.
Your problem can be solved using a MutableLiveData object without blocking the UI thread.
Let's start assuming you have a main class named MainThread where your getDate method lives.
In this class first create the following MutableLiveData object:
private MutableLiveData<String> date = new MutableLiveData<>();
The object above will be updated with the date value as soon as it's available to your program.
Next create/update the method that'll make a call to the getDate method (which we'll keep for simplicity's sake):
private void exampleDateMethod() {
// first create an observer; in the observer you put the code that does something with the Date
date.observe(this, new Observer<String>() {
#Override
public void onChanged( String date ) {
// this is where you do something with the date, an example:
findViewById( R.id.date_view ).setText( date );
}
});
// pass the MutableLiveData to the getDate method so that its value can be updated:
getDate( date );
}
And change the getDate method to pass the Date to the MutableLiveData object:
private void getDate( MutableLiveData<String> liveDate ){
internetDate.getCurrentDate(new InternetDate.OnGetDate() {
#Override
public void onSuccess(String date) {
// set the value of the MutableLiveData object, this will notify the observer and execute the code in its onChanged method
liveData.setValue( date );
}
});
}
I am writing simple code to asynchronously write logs to file, but find it difficult to figure out one issue.
I get java.util.NoSuchElementException in logNodes.removeFirst(). How can this happen if I check if the list is empty?
This issue mostly occurs if I log very frequently.
If anyone can explain to me why is this happening, it would be very appreciated.
My code:
private static class FileLogger extends Thread {
private File logFile;
private PrintWriter logWriter;
private final LinkedList<LogNode> logNodes = new LinkedList<>();
public FileLogger(Context context) {
String dateString = (String) DateFormat.format("yyyy-MM-dd_HH:mm:ss", new Date());
File logsDir = new File(context.getCacheDir(), "logs");
if (logsDir.exists()) {
for (File file : logsDir.listFiles()) {
file.delete();
}
}
try {
logFile = new File(logsDir, dateString + ".log");
if (!logFile.exists()) {
logFile.getParentFile().mkdirs();
logFile.createNewFile();
}
logWriter = new PrintWriter(new FileOutputStream(logFile));
start();
} catch (IOException ignored) {
}
}
public void log(Date date, String tag, String msg) {
if (isAlive()) {
logNodes.addLast(new LogNode(date, tag, msg));
synchronized (this) {
this.notify();
}
}
}
#Override
public void run() {
while (true) {
if (logNodes.isEmpty()) {
try {
synchronized (this) {
this.wait();
}
} catch (InterruptedException e) {
logWriter.flush();
logWriter.close();
return;
}
} else {
LogNode node = logNodes.removeFirst();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
logWriter.println(String.format(
"%s %s.%s", dateFormat.format(node.date), node.tag, node.msg
));
logWriter.flush();
}
}
}
private class LogNode {
final Date date;
final String tag;
final String msg;
public LogNode(Date date, String tag, String msg) {
this.date = date;
this.tag = tag;
this.msg = msg;
}
}
}
Reason
You did not synchronize mutiple log threads.
Suppose you have thread1 and thread2:
thread1 has written node1 into the queue.
FileLogger noticed node1 when it call isEmpty, while thread2 did
not notice it.
thread2 think this list is empty, and let the list's first and
last node be node2, which means node1 has be overwritten.
Since you did not has any other synchronization, node2 might not be noticed by FileLogger, NoSuchElementException will be thrown.
Solution
Instead implementing a blocking queue yourself, try use BlockigQueue provided by java.util.concurrent, let it do the synchronization for you.
private static class FileLogger extends Thread {
private File logFile;
private PrintWriter logWriter;
private final BlockingQueue<LogNode> logNodes = new LinkedBlockingQueue<>();
public FileLogger(Context context) {
String dateString = (String) DateFormat.format("yyyy-MM-dd_HH:mm:ss", new Date());
File logsDir = new File(context.getCacheDir(), "logs");
if (logsDir.exists()) {
for (File file : logsDir.listFiles()) {
file.delete();
}
}
try {
logFile = new File(logsDir, dateString + ".log");
if (!logFile.exists()) {
logFile.getParentFile().mkdirs();
logFile.createNewFile();
}
logWriter = new PrintWriter(new FileOutputStream(logFile));
start();
} catch (IOException ignored) {
}
}
public void log(Date date, String tag, String msg) {
if (isAlive()) {
logNodes.add(new LogNode(date, tag, msg));
}
}
#Override
public void run() {
while (true) {
try {
LogNode node = logNodes.take();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
logWriter.println(String.format(
"%s %s.%s", dateFormat.format(node.date), node.tag, node.msg
));
logWriter.flush();
} catch (InterruptedException e) {
logWriter.flush();
logWriter.close();
return;
}
}
}
}
I am running SonarQube 5 for code quality check after integrating the code with Maven.
Sonar is complaining that I should:
Either log or rethrow this exception.
in following piece of code:
public static Date convertStringtoDate(String stringDate) {
stringDate = StringUtils.trimToNull(stringDate);
SimpleDateFormat dfm = new SimpleDateFormat("dd-MMM-yyyy");
Date date = null;
if (stringDate != null) {
try {
date = dfm.parse(stringDate);
} catch (Exception e) {
logger.info("Cannot convert String to Date: ",convertStringtoDate(e.getMessage()));
}
}
return date;
}
What am I missing here?
First of all, is this behaviour correct? Seems a bit weird that you are trying to call convertStringtoDate on the exception message as well.
Secondly, I had the same problem with Sonar recently. Seems like you need to pass the whole exception as a parameter to the logger, instead of e.getMessage() for Sonar to realize you are logging the exception.
Try this instead:
public static Date convertStringtoDate(String stringDate){
stringDate = StringUtils.trimToNull(stringDate);
SimpleDateFormat dfm = new SimpleDateFormat("dd-MMM-yyyy");
Date date = null;
if(stringDate!=null){
try {
date = dfm.parse(stringDate);
} catch (Exception e) {
logger.info("Cannot convert String to Date: ", e);
}
}
return date;
}
As we know, simpleDateFormat are not thread-safe. When facing multi-thread, simpleDateFormat may throw some exceptions. So, I decided to use joda-time instead.
However, when I use joda-time together with simpleDateFormat, some thing strange happened.
Expect result:
simpleDateFormat throws exception, joda-time parsed successfully.
Actual result:
both parsed successfully.
Look at the code I wrote for test below.
public class MultiThreadDateTest {
private static SimpleDateFormat dformat = new SimpleDateFormat("yyyy-MM-dd");
private static DateTimeFormatter format = DateTimeFormat.forPattern("yyyy-MM-dd");
private static final int THREAD_SIZE = 4;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < THREAD_SIZE; i++) {
new Thread(new JavaDateThread()).start();
new Thread(new JodaDateThread()).start();
}
}
private static class JavaDateThread implements Runnable {
#Override
public void run() {
try {
Date date = dformat.parse("1999-01-01");
System.out.println(Thread.currentThread().getId() + ": " + date);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
private static class JodaDateThread implements Runnable {
#Override
public void run() {
Date date = format.parseDateTime("2000-01-01").toDate();
System.out.println(Thread.currentThread().getId() + ": " + date);
}
}
}
i was searching how to convert a string to a date, so i've found some examples on stacko. . So i used SimpleDateFormat and tried to parse but my compiler (Gradle from AndroidStudio) send me this error : Unhandled exception : java.text.ParseException.
There is my code :
public static int compareDate(String sdate1, String sdate2) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.FRANCE);
Date date1 = simpleDateFormat.parse(sdate1); // there is the error
[...]
}
Why is there an error? Someone can explain that to me?
I'm a beginner in java and i'm sorry for my bad english, and i hope someone can help me on this.
Thanks
The parse method throws a ParseException. You need to insert a catch block or your method should throw ParseException in order to get rid of the error:
public static int compareDate(String sdate1, String sdate2) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.FRANCE);
try {
Date date1 = simpleDateFormat.parse(sdate1);
} catch (ParseException e) { // Insert this block.
// TODO Auto-generated catch block
e.printStackTrace();
}
}
OR
public static int compareDate(String sdate1, String sdate2) throws ParseException{
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.FRANCE);
Date date1 = simpleDateFormat.parse(sdate1);
}