Related
I downloaded my extended listening history from Spotify and I am trying to make a program to turn the data into a list of artists without doubles I can easily make sense of. The file is rather huge because it has data on every stream I have done since 2016 (307790 lines of text in total). This is what 2 lines of the file looks like:
{"ts":"2016-10-30T18:12:51Z","username":"edgymemes69endmylifepls","platform":"Android OS 6.0.1 API 23 (HTC, 2PQ93)","ms_played":0,"conn_country":"US","ip_addr_decrypted":"68.199.250.233","user_agent_decrypted":"unknown","master_metadata_track_name":"Devil's Daughter (Holy War)","master_metadata_album_artist_name":"Ozzy Osbourne","master_metadata_album_album_name":"No Rest for the Wicked (Expanded Edition)","spotify_track_uri":"spotify:track:0pieqCWDpThDCd7gSkzx9w","episode_name":null,"episode_show_name":null,"spotify_episode_uri":null,"reason_start":"fwdbtn","reason_end":"fwdbtn","shuffle":true,"skipped":null,"offline":false,"offline_timestamp":0,"incognito_mode":false},
{"ts":"2021-03-26T18:15:15Z","username":"edgymemes69endmylifepls","platform":"Android OS 11 API 30 (samsung, SM-F700U1)","ms_played":254120,"conn_country":"US","ip_addr_decrypted":"67.82.66.3","user_agent_decrypted":"unknown","master_metadata_track_name":"Opportunist","master_metadata_album_artist_name":"Sworn In","master_metadata_album_album_name":"Start/End","spotify_track_uri":"spotify:track:3tA4jL0JFwFZRK9Q1WcfSZ","episode_name":null,"episode_show_name":null,"spotify_episode_uri":null,"reason_start":"fwdbtn","reason_end":"trackdone","shuffle":true,"skipped":null,"offline":false,"offline_timestamp":1616782259928,"incognito_mode":false},
It is formatted in the actual text file so that each stream is on its own line. NetBeans is telling me the exception is happening at line 19 and it only fails when I am looking for a substring bounded by the indexOf function. My code is below. I have no idea why this isn't working, any ideas?
import java.util.*;
public class MainClass {
public static void main(String args[]){
File dat = new File("SpotifyListeningData.txt");
List<String> list = new ArrayList<String>();
Scanner swag = null;
try {
swag = new Scanner(dat);
}
catch(Exception e) {
System.out.println("pranked");
}
while (swag.hasNextLine())
if (swag.nextLine().length() > 1)
if (list.contains(swag.nextLine().substring(swag.nextLine().indexOf("artist_name"), swag.nextLine().indexOf("master_metadata_album_album"))))
System.out.print("");
else
try {list.add(swag.nextLine().substring(swag.nextLine().indexOf("artist_name"), swag.nextLine().indexOf("master_metadata_album_album")));}
catch(Exception e) {}
System.out.println(list);
}
}
Find a JSON parser you like.
Create a class that with the fields you care about marked up to the parsers specs.
Read the file into a collection of objects. Most parsers will stream the contents so you're not string a massive string.
You can then load the data into objects and store that as you see fit. For your purposes, a TreeSet is probably what you want.
Your code will throw a lot of exceptions only because you don't use braces. Please do use braces in each blocks, whether it is if, else, loops, whatever. It's a good practice and prevent unnecessary bugs.
However, everytime scanner.nextLine() is called, it reads the next line from the file, so you need to avoid using that in this way.
The best way to deal with this is to write a class containing the fields same as the json in each line of the file. And map the json to the class and get desired field value from that.
Your way is too much risky and dependent on structure of the data, even on whitespaces. However, I fixed some lines in your code and this will work for your purpose, although I actually don't prefer operating string in this way.
while (swag.hasNextLine()) {
String swagNextLine = swag.nextLine();
if (swagNextLine.length() > 1) {
String toBeAdded = swagNextLine.substring(swagNextLine.indexOf("artist_name") + "artist_name".length() + 2
, swagNextLine.indexOf("master_metadata_album_album") - 2);
if (list.contains(toBeAdded)) {
System.out.print("Match");
} else {
try {
list.add(toBeAdded);
} catch (Exception e) {
System.out.println("Add to list failed");
}
}
System.out.println(list);
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I need help extracting a JSON array string into an array of objects so that it can be later processed.
The JSON string is embedded as a value within a pipe delimited string that is itself an XML element value.
A sample string is as below
<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}</MSG>
How can I extract the JSON properties and store them in separate arrays like
Format[0] =BMP
Position[0] =RIGHT_INDEX
Data[0]=Qk12WQEAAAAAADYAAAA=
Format[1] =BMP
Position[1]=LEFT_INDEX
Data[1]= Qk12WQEADoAAAA
These objects would then be passed to a separate function like below
FingerprintImage(Format[0],Position[0],Data[0]);
// ...
FingerprintImage(Format[1],Position[1],Data[1]);
// ...
public FingerprintImage(String format, String position, String data) {
setFormat(format);
setPosition(position);
setData(data);
}
I am not a java developer, the following is hopefully helpful to yourself or others who can provide more succinct syntax in java.
Firstly, we should identify there different layers of data serialization going on with your value:
<MSG></MSG> This is an outer XML element, so the first step is to interpret this value as an XML fragment and extract the XML Value.
The reason that we use XML deserialization at this top level, and not just use the string position, is that the inner values may have been XML escaped, so we need to parse the inner value using the XML encoding rules.
This leaves us with the strimg value: registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}
The next level is pipe-delimited, which is the same as CSV, except the escape character is a | and usually there is no other encoding rules, as | isn't considered part of the normal lexical domain and we shouldn't need any further escaping.
You could therefore split this string into an array.
The value we are interested in is the 15th element in the array, eithe you know this in advance, or you could simply iterate through the elements to find the first one that starts with {
This leaves a JSON value: {"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}
Now that we have isolated the inner value in JSON format, the usual thing to do next is deserialize this value into an object.
I know OP is asking for arrays, but we can realize JSON objects as arrays if we really want to with the right tools.
In C# the above process is pretty simple, I'm sure it should be in Java as well, but my attempts keep throwing errors.
So, lets instead assume (I know... Ass-U-Me...) that there is only ever a single JSON value in the pipe-delimited array, with this knoweldge we can isolate the JSON using int String.IndexOf(str)
String xml = "<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{\"biometrics\":{\"fingerprints\":{\"fingerprints\":[{\"position\":\"RIGHT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEAAAAAADYAAAA=\"}},{\"position\":\"LEFT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEADoAAAA\"}}]}}}</MSG>";
int start = xml.indexOf('{');
int end = xml.lastIndexOf('}') + 1; // +1 because we want to include the last character, so we need the index after it
String json = xml.substring(start, end);
results in: {"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}
Formatted to be pretty:
{
"biometrics": {
"fingerprints": {
"fingerprints": [
{
"position": "RIGHT_INDEX",
"image": {
"format": "BMP",
"resolutionDpi": "508",
"data": "Qk12WQEAAAAAADYAAAA="
}
},
{
"position": "LEFT_INDEX",
"image": {
"format": "BMP",
"resolutionDpi": "508",
"data": "Qk12WQEADoAAAA"
}
}
]
}
}
}
One way would be to create a class structure that matches this JSON value, then we can simply .fromJson() for the whole value, instead, lets meet halfway so we only need to define the inner class structure for the data we will actually use.
Now from this structure we can see there is an outer object that only has a single property called biometrics, this value is again an object witha single property called fingerprints. The value of this property is another object that has a single property called fingerprints except that this time it has an array value.
The following is a proof in Java, I have included first an example using serialization (using the gson library) and after that a similar implementation using only the simple-JSON library to read the values in arrays.
Try it out on JDoodle.com
MyClass.java
import java.util.*;
import java.lang.*;
import java.io.*;
//import javax.json.*;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import com.google.gson.Gson;
public class MyClass {
public static void main(String args[]) {
String xml = "<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{\"biometrics\":{\"fingerprints\":{\"fingerprints\":[{\"position\":\"RIGHT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEAAAAAADYAAAA=\"}},{\"position\":\"LEFT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEADoAAAA\"}}]}}}</MSG>";
int start = xml.indexOf('{');
int end = xml.lastIndexOf('}') + 1; // +1 because we want to include the last character, so we need the index after it
String jsonString = xml.substring(start, end);
JSONParser parser = new JSONParser();
Gson gson = new Gson();
try
{
// locate the fingerprints inner array using simple-JSON (org.apache.clerezza.ext:org.json.simple:0.4 )
JSONObject jsonRoot = (JSONObject) parser.parse(jsonString);
JSONObject biometrics = (JSONObject)jsonRoot.get("biometrics");
JSONObject fpOuter = (JSONObject)biometrics.get("fingerprints");
JSONArray fingerprints = (JSONArray)fpOuter.get("fingerprints");
// Using de-serialization from gson (com.google.code.gson:gson:2.8.6)
FingerPrint[] prints = new FingerPrint[fingerprints.size()];
for(int i = 0; i < fingerprints.size(); i ++)
{
JSONObject fpGeneric = (JSONObject)fingerprints.get(i);
prints[i] = gson.fromJson(fpGeneric.toString(), FingerPrint.class);
}
// Call the FingerprintImage function using the FingerPrint objects
System.out.print("FingerPrint Object Index: 0");
FingerprintImage(prints[0].image.format, prints[0].position, prints[0].image.data );
System.out.println();
System.out.print("FingerPrint Object Index: 1");
FingerprintImage(prints[1].image.format, prints[1].position, prints[1].image.data );
System.out.println();
// ALTERNATE Array Implementation (doesn't use gson)
String[] format = new String[fingerprints.size()];
String[] position = new String[fingerprints.size()];
String[] data = new String[fingerprints.size()];
for(int i = 0; i < fingerprints.size(); i ++)
{
JSONObject fpGeneric = (JSONObject)fingerprints.get(i);
position[i] = (String)fpGeneric.get("position");
JSONObject image = (JSONObject)fpGeneric.get("image");
format[i] = (String)image.get("format");
data[i] = (String)image.get("data");
}
System.out.print("Generic Arrays Index: 0");
FingerprintImage(format[0], position[0], data[0] );
System.out.println();
System.out.print("Generic Arrays Index: 1");
FingerprintImage(format[1], position[1], data[1] );
System.out.println();
}
catch (ParseException ignore) {
}
}
public static void FingerprintImage(String format, String position, String data) {
setFormat(format);
setPosition(position);
setData(data);
}
public static void setFormat(String format) {
System.out.print(", Format=" + format);
}
public static void setPosition(String position) {
System.out.print(", Position=" + position);
}
public static void setData(String data) {
System.out.print(", Data=" + data);
}
}
output
FingerPrint.java
public class FingerPrint {
public String position;
public FingerPrintImage image;
}
FingerPrintImage.java
public class FingerPrintImage {
public String format;
public int resolutionsDpi;
public String data;
}
Deserialization techniques are generally considered superior to forced/manual parsing especially when we need to pass around references to multiple parsed values. In the above example, by simply reading format, position and data into separate arrays, the relationship between them has become de-coupled, through our code implementation we can still use them together as long as we use the same array index, but the structure no longer defines the relationship between the values. De-serializing into a typed structure preserves the relationship between values and simplifies the task of passing around values that are related to each other.
update
If you used serialization, then you could pass through the equivalent FingerPrint object to any methods that need it, instead of passing through the related values individually, further to this you could simply pass around the entire array of FingerPrint objects.
public static void FingerprintImage(FingerPrint print) {
setFormat(print.image.format);
setPosition(print.position);
setData(print.image.data);
}
To process multiple FingerPrint objects in a batch, change the method to accept an array: FingerPrint[]
You could use the same technique to process arrays or each of the Format, Postion and Data, though it is really poor practise to do so. Passing around multiple arrays and expecting the receiving code to know that each of the arrays is supposed to be interpreted in sync, that is the same index in each array corresponds to the same finger print, this level of implementation detail is too ambiguous and will lead to maintenance nightmares down the track, its far better to learn and become proficient in OO concepts and creating business objects for passing around related data elements, instead of packaging everything into disassociated arrays.
The following code can assist you in processing multiple items using OPs array method but it should highlight why the practise is a bad habit to pickup:
public static void FingerprintImage(String[] formats, String[] positions, String[] datas) {
// now you must iterate each of the arrays using the same index
// however as there are no restrictions on the arrays, for each array
// and each index we should be checking that the array has not gone out
// of length.
}
From an OO point of view, passing through multiple arrays like this raises a number of issues, firstly, the developer will simply need to know that the same index must be used in each array to retrieve correlated information.
The next important issue is error handling...
If datas only has 1 element, but positions has 2 elements, which of the 2 elements does the 1 data element belong to? Or does this indicate that the same data should be used for both?
There are many other issues, consider when you expect 3 elements...
While you can get away with what seems like a shortcut in code if you really need to, you really shouldn't unless you absolutely understand what you are doing, you fully document the related code and you are taking responsibility for the potential fall out down the track.
I'm trying to make an application which would read a word file (docx) and do some stuff with it. So far, I've done pretty much everything except for to identify bullets.
I can find isBold(), isItalic(), isStrike() but I cannot seem to find isBullet()
can anyone please tell me how to identify bullets?
the application is built in Java
There's no isBullet() method, because list styling in Word is quite a lot more complicated than that. You have different indent levels, different styles of bullets, numbered lists and bulleted lists etc
Probably the easiest method for you to call for your use case is XWPFParagraph.html.getNumFmt():
Returns numbering format for this paragraph, eg bullet or lowerLetter. Returns null if this paragraph does not have numeric style.
Call that, and if you get null it isn't a list, and if it is, you'll know if it's bulleted, number, letter etc
You can use below code for getting list of all the bullets from the word document. I have used apache poi's XWPF api.
public class ListTest {
public static void main(String[] args) {
String filename = "file_path";
List<String> paraList = new ArrayList<String>();
try {
// is = new FileInputStream(fileName);
XWPFDocument doc =
new XWPFDocument(OPCPackage.open(filename));
List<XWPFParagraph> paragraphList = doc.getParagraphs();
for(XWPFParagraph para :paragraphList) {
if((para.getStyle()!=null) && (para.getNumFmt() !=null)) {
paraList.add(para.getText());
}
for(String bullet :paraList) {
System.out.println(bullet);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
I'm stuck on this program I'm making for school. Here's my code:
public static void experiencePointFileWriter() throws IOException{
File writeFileResults = new File("User Highscore.txt");
BufferedWriter bw;
bw = new BufferedWriter(new FileWriter(writeFileResults, true));
bw.append(userName + ": " + experiencePoints);
bw.newLine();
bw.flush();
bw.close();
FileReader fileReader = new FileReader(writeFileResults);
char[] a = new char[50];
fileReader.read(a); // reads the content to the array
for (char c : a)
System.out.print(c); // prints the characters one by one
fileReader.close();
}
The dilemma I'm facing is how can I sort new scores with the scores in writeFileResults by the numerical value of int experiencePoints? If you're wondering about the variables userName is assigned by a textfield.getText method, and an event happens when you press one of 36 buttons which launches a math.Random statement with one of 24 possible outcomes. They all add different integer numbers to experiencePoints.
Well, I don't want to do your homework, and this does seem introductory so I'd like to give you some hints.
First, there's a few things missing:
We don't have some of the variables you've given us, so there is no type associated with oldScores
There is no reference to userName or experiencePoints outside this method call
If you can add this information, it would make this process easier. I could infer things, but then I might be wrong, or worse yet, have you learn nothing because I did your assignment for you. ;)
EDIT:
So, based on extra information, you're data file is holding an "array" of usernames and experience values. Thus, the best way (read: best design, not shortest) would be to load these into custom objects then write a comparator function (read: implement the abstract class Comparator).
Thus, in pseudo-Java, you'd have:
Declare your data type:
private static class UserScore {
private final String name;
private final double experience;
// ... fill in the rest, it's just a data struct
}
In your reader, when you read the values, split each line to get the values, and create a new List<UserScore> object which contains all of the values read from the file (I'll let you figure this part out)
After you have your list, you can use Collections#sort to sort the list to be the correct order, here would be an example of this:
// assuming we have our list, userList
Collections.sort(userList, new Comparator<UserScore>() {
public int compare(UserScore left, UserScore right) {
return (int)(left.getExperience() - right.getExperience()); // check the docs to see why this makes sense for the compare function
}
}
// userList is now sorted based on the experience points
Re-write your file, as you see fit. You now have a sorted list.
I've this question from an assignment to create a Store which rent out books, using a Store.java and Book.java. I've finished this assignment, but I'm curious for better algorithm to a specific part.
--
Book.java
public class Book {
private String name;
Book(String name)
this.name = name;
public String getName()
return name;
}
Store.java
Inside main();
Book bookObj[] = new Book[3]; //Create 3 Array of Object.
bookObj[0] = new Book("Game Over");
bookObj[1] = new Book("Shrek");
bookObj[2] = new Book("Ghost");
Scanner console = new Scanner(System.in)
input = console.nextLine();
Assuming, input = Devil.
Now, I need to do a simple search to check whether the specific book exist.
Example:
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
}
Apparently, this is a for loop that cycles through the array of object and checks whether such Book exist. Now, the problem arise when I want to give an output that the Book was not found.
Example:
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
else
System.out.println("Book not Found!");
}
The problem with the above code is that Book not Found would be printed thrice. My goal is to avoid such problem. I do have solutions to this, but I'm still in search for a better one to use that utilizes getName(), which in my opinion still has room to improve.
Usually, in structural programming, I would do the following,
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
else if(i == bookObj.length - 1)
System.out.println("Book not Found!");
}
This is useful to tell whether it's the end of the loop, and the search has ended, but there was no successful result from the search.
How should I think of it in Object Oriented way?
All in all, my question is,
Is there a better way to write the above code rather than checking that it's the end of the line?
Is there a better way to utilize getName() method or to use other methods?
You should loop through the array and use an index / boolean flag to store whether or not the book is found. Then print the message in the end, based on the index / flag value.
int foundAtIndex = -1;
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input)) {
foundAtIndex = i; // store the actual index for later use
break; // no need to search further
}
}
if(foundAtIndex >= 0)
System.out.println("Book Found!");
else
System.out.println("Book not Found!");
Alternatively (unless your assignment specifically requires using an array) you should prefer a Set, which can do the search for you with a single call to contains().
How should I think of it in Object Oriented way?
When looking at a single method, there is not much difference between procedural and OO style. The differences start to appear at a higher level, when trying to organize a bunch of conceptually related data and methods that operate on these.
The OO paradigm is to tie the methods to the data they operate on, and encapsulate both into coherent objects and classes. These classes are preferably representations of important domain concepts. So for your book store, you may want to put all book related code into your Book class. However, the above search method (and the collection of books it operates on) is not related to any particular book instance, so you have different choices:
put both the collection of books and the search method into Store (probably as regular members), or
put them into Book as static members.
The first choice is more natural, so I normally would prefer that. However, under specific circumstances the second option might be preferable. In (OO) design, there are hardly ever clean "yes/no" answers - rather tradeoffs between different options, each having their own strengths and weaknesses.
You could introduce state and remember whether you have found the book or not.
If you're not using Java 1.4 or earlier, you could also use the foreach loop syntax:
boolean bookFound = false;
for(Book currentBook : bookObj) {
if(currentBook.getName().equals(input))
//TODO: see above
}
Also, I would suggest looking into the Collections library, and replace your array with a list or set:
Set<Book> books = new HashSet<Book>();
books.put(new Book("Game Over"));
books.put(new Book("Shrek"));
books.put(new Book("Ghost"));
And, while were at it, you could also think about when two books are equal and override equals() and hashCode() accordingly. If equal() would be changed to check the title, you could simply use books.contains(new Book(input)); and have the libraries do the work for you.
To solve the problem in a better way you must understand that the power of Java comes not from the language itself but from the Java Framework.
You should learn the usage of the Java Collection classes (never work with arrays anymore). Then you will be able to solve the search with just one line of code:
ArrayList<Book> listOfBooks;
// init your list here
listOfBooks.contains(new Book(input));
To make this work, you must also learn how to correctly implement the equals() method of your Book class.
Happy learning!
Here is a working solution :
import java.util.Scanner;
public class Store {
private static class Book {
private String name;
Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) {
String input;
Book[] bookObj = new Book[3];
bookObj[0] = new Book("Game Over");
bookObj[1] = new Book("Shrek");
bookObj[2] = new Book("Ghost");
Scanner console = new Scanner(System.in);
input = console.nextLine();
boolean found = false;
int i = 0;
while(!found && i < bookObj.length) {
if(bookObj[i].getName().equals(input)) {
System.out.println("Book Found at position : " + i);
found = true;
} else {
i++;
}
}
if(!found) {
System.out.println("Book not Found!");
}
// Here i contains the indice of the element found in the array.
}
}
You've gotten some pretty good advice thus far. You asked if there was a more Object Oriented way of thinking about the problem so I thought I'd try and shed some light on it. As Peter already mentioned at this level of the design it's a single method implementation so the approach is going to be fairly similar as say a procedural approach. What's the advantage? In a word reuse. If you needed to find a book by name in lots of places then moving the code to it's own class will help.
So what you have is a single Book instance to encapsulate behavior around a single book, but you want to have behavior about multiple books, or a collection of books. You can keep the data (array of books), and the method that account on them separate as you outlined in your program. However, if we wanted to collect a place for doing behavior on a collection of books we can define a new class. Let's call it Library, and we might do something like the following:
public class Library {
private Book[] books;
private bookCount = 0;
public Library( int numberOfTotalBooks ) {
books = new Book[numberOfTotalBooks];
}
public boolean addBook( Book book ) {
if( bookCount < book.length ) {
books[bookCount++] = book;
return true;
}
return false;
}
public Book findByTitle( String title ) {
for( int i = 0; i < bookCount; i++ ) {
if( books[i].getTitle().equals( title ) ) {
return books[i];
}
}
// didn't find one
return null;
}
}
So a couple of things to note about doing things this way. One is that when we work with a Library we don't know there is an Array back there. We could use an array, a Set, a List, or a database (most common). The point being the code that calls these functions just works with the interface of Library (not a literal Java interface, but the method signature of Library). Also this is a higher level interface. We don't worry about iterating over the books, doing for loops, if statements, etc. We just call a method saying "Hey find this book title in the Library". How that's done we don't care. This is the basic tenant of Object Orientation called encapsulation, and it's deceptively powerful. It's really about how we delegate responsibility in our program, and give the details of a job to individual class or classes. If Library had only public members (i.e. books and bookCount), or getter/setters then the client wouldn't be getting any advantages because the client would still have to do all the heavy lifting. The trick to OO is figuring out what can be delegated out of an object, without creating problems. This takes practice, and experience.
The second thing here is we've separated the presentation from the act of finding a book. The method you wrote assumed the next step which was to print "Hey we found it." However, Library object simply returns the Book to you when it finds it, or null if it didn't. That makes it possible to print to the console, display in a GUI, or serialize it to a JSON stream in a server. The act of finding a book is separate from the visualization. This is another important aspect of programming in general, but some what related to object orientation and encapsulation. This is typically called separation of concerns. The console application has concerns about supporting the UI, and printing the console. While the Library just manages cataloging and managing the book collection. How those details are performed neither cares.
In the end Library is a reusable class. We can use it in a console application, desktop, web, or middleware server. More importantly is we can also reuse the calls to findByTitle or addBooks from multiple locations within a single program. Also by putting the methods with the data we create a barrier to where that function can be used. You can't do it anywhere in your program. You have to have a reference to Library. If you don't have reference to a Library instance then you shouldn't be calling it. This can be troublesome to new developers because they lack the experience to properly organize their programs to not get into trouble with this (then they start doing value objects, creating statics, singletons, etc and things turn into a big ball of mud). It's a double edged sword.
One more thing I'd like to point out is say we wanted to model two Libraries. We have a Library uptown and downtown, and we want to allow people to check out books from either Library. With OO that's really easy to represent:
Library uptown = new Library( 50 );
Library downtown = new Library( 100 );
Now we can check out books from one or the other. And I didn't use statics (i.e. global variables) so reusing that logic is really easy. These are the basics of OO so they are really deep topics. Strange how I can write so much on very simple topics. Anyway I hope this helped you understand your program a little deeper, and see how you can use OO to help you.
chubbsondubs came closest to giving a correct answer to this question
What he missed is that his algorithm is incorrect because it contains two tests, when only one is needed. The correct code requires only 3 statements and is as follows:
public boolean zLibaryContains( String title ) {
books[bookCount] = title;
int xBook = 0;
while( true )
if( books[xBook].getTitle().equals( title ) )
return xBook != bookCount;
else xBook++;
}
Noticeably smaller and faster than all other solutions. Simplify, simplify, simplify.
Object-oriented code is a crutch to support poor designs that would otherwise be too complex to understand. The goal is write code that is so easy to understand and maintain that OO is unnecessary and would make the program worse. When your program can be improved by adding OO, it means you are doing something wrong to begin with.