I have this method which takes n number of arguments and search for a book in an arrayList using couple of arguments. .
How can i make it smaller?
How to sort books by category or author?
thank you in advance.
Here is my method
// search for a book using multiple criteria
static void bookSearch(String... varg) { // take varg as parameter
String title = ""; // place holders
String author = "";
if (varg.length > 1) { // check varg length
title = varg[0]; // if it is greater than 1 initialize needed arguments
author = varg[1];
} else {
title = varg[0]; // else initialize the first argument
}
for (Book book : bookList) {
/*
* if the title is the same and there is a second argument that
* match author's name print found it
*/
if (book.getTitle().equals(title)) {
if (author.isEmpty() ^ (book.getAuthor().getfName() == author)) {
System.out.println(" \"" +
title +
"\" founded at: " +
bookList.indexOf(book));
break;
}// end of if
} else if (bookList.indexOf(book) == bookList.size() - 1) {// if not found
System.out.println("cant find \"" + title);
}// end of else
} // end of for loop
} //end of search method
In Java8 you can use lambdas and functions to get flexible filter book function.
E.g. you have following Book class:
class Book {
private String author;
private String title;
}
The book filter function could look like this:
BiFunction<List<Book>, Predicate<Book>, List<Book>> BOOK_FILTER =
(books, fields) -> books.stream().filter(fields).collect(Collectors.toList());
Then, all you need is just build required Predicate and use this function.
public static List<Book> findBookByPredicate(List<Book> books, String author, String title) {
Predicate<Book> byAuthor = book -> book.getAuthor().equals(author);
Predicate<Book> byTitle = book -> book.getTitle().equals(title);
return BOOK_FILTER.apply(books, byAuthor.and(byTitle));
}
As you can see, you're not limited only certain number of Book fields. You can combine it as you like; BOOK_FILTER function stays the same.
You can default title to varg[0] and set author if varg.length is greater than one with a ternary. I would prefer a standard loop with a index counter (since otherwise you must search again to determine the index). Next, you need to complete the loop before declaring the title isn't found (I would use a boolean to maintain that state). Next, you logically need an or (not a xor) to check that the author argument is present and not empty before checking the book author. I would prefer formatted io. Like,
static void bookSearch(String... varg) {
String title = varg[0], author = varg.length > 1 ? varg[1] : "";
boolean found = false;
for (int i = 0; i < bookList.size(); i++) {
Book book = bookList.get(i);
if (book.getTitle().equals(title)
&& (author.isEmpty() || book.getAuthor().getName().equals(author))) {
System.out.printf("\"%s\" found at: %d%n", title, i);
found = true;
break;
}
}
if (!found) {
System.out.printf("cant find \"%s\"%n", title);
}
}
You can use java 8 lamda expression for this.
Ex.
List<String> lines = Arrays.asList("spring", "node", "mkyong");
//Here pass your collection and filter as per your requirement
List<String> result = lines.stream()
.filter(line -> !"mkyong".equals(line))
.collect(Collectors.toList());
Aside from using lambda expression, other way to make your code a little shorter would be to implement equals method for your Book class where you can compare two Book objects for equality by their title and author. Then instead of:
if (book.getTitle().equals(title)) {
if (author.isEmpty() ^ (book.getAuthor().getfName() == author)) {
System.out.println(" \"" + title + "\" founded at: "
+ bookList.indexOf(book));
break;
}// end of if
you can just use:
Book searchForBook = new Book();
searchForBook.setAuthor(author); //ins
searchForBook.setTitle(title);
for (Book book : bookList) {
if (book.equals(searchForBook)){
System.out.println(" \"" + title + "\" found at: "
+ bookList.indexOf(book));
break;
}
You can also make the creation of object searchForBook one line only, if you add proper constructors in your Book class.
On sorting the ArrayList - you can either make Book implement Comparable and use Collections.sort(bookList) or use a Comparator instead and use Comparator and again use Collections.sort before you use the collection, to have it sorted the way you want.
Your code can be shortened like this:
static void bookSearch (String... varg) {
String author = "";
String title = varg[0];
if (varg.length > 1) {
author = varg[1];
}
for (Book book : bookList) {
if (book.getTitle().equals (title)) && (author.isEmpty() || (book.getAuthor().getfName() == author)) {
System.out.println(" \"" + title + "\" founded at: " + bookList.indexOf(book));
return;
}
}
System.out.println("cant find \"" + title);
}
Title doesn't need to be in if and else branch. Just initialize on declaration.
Take the ternary operator from Elliot if you like
Your outer if only has the inner if (title/author). This can be replaced by &&.
Just return instead of breaking.
With the premature return, you don't need else anymore.
A boolean predicate 'matches' which does the same thing in the Book class might be preferred. Sorting can be a good idea, if you don't have to resort by different criteria often and if you search for multiple books - then it can pay off.
A boolean return or a return of the index, where the book was found, might be more flexible. But for reporting the index, I would use a classical for loop, where you get it by the same iteration.
Returning the index would allow to remove the System.outs, so that the caller can decide, how to handle the event: Order a book via net, print to stdout, output with Swing oder JavaFX or whatever.
A pure compareTo would allow efficient search algorithms to find many book in big lists fast and smooth integration in the new Stream collections.
Using varg seems to be a bad idea to me, since it opens the door wide for getting the parameter order wrong.
int bookSearch (String title, Optional[String] author) {
expresses more clearly what you want - many IDEs support parameter names.
Related
I'm currently making a novel reader/editor in java using JSON. I've made the reader part with no problem, but the JSON serialization in the editor is giving me problems.
The idea is to add or set an object to an ArrayList like this:
ArrayList<Chapters> allChapters = new ArrayList<>();
private void TAContentKeyTyped(java.awt.event.KeyEvent evt) {
Chapters newChapter = new Chapters(LSChapters.getSelectedValue(), TAContent.getText());
if (allChapters.contains(newChapter)) {
allChapters.set(0, newChapter);
}
else {
allChapters.add(newChapter);
}
String json = gson.toJson(allChapters);
Iterator allChaptersIterator = allChapters.iterator();
while (allChaptersIterator.hasNext()) {
System.out.println(allChaptersIterator.next().toString());
}
System.out.println(json);
}
which outputs this when I press backspace 3 times:
Chapter: Test Content:
Chapter: Test Content:
Chapter: Test Content:
[{"chapter":"Test","content":""},{"chapter":"Test","content":""},{"chapter":"Test","content":""}]
As you can see, instead of putting all inputs with the same chapter name into a single element, the code uses the .add() method instead of the .set() method every time despite putting a .contains() method on the if. Admittedly I didn't expect this approach to work, but I have no idea how to approach this at all.
The desired output should look like this:
Chapter: Test Content: This is content 1
Chapter: Test 2 Content: This is content 2
[{"chapter":"Test","content":"This is content 1"},{"chapter":"Test 2","content":"This is content 2"}]
Where every chapter with the same name is stored in a single element no matter how many keys were pressed.
Thank you in advance.
The Chapters class look like this:
public class Chapters {
private String chapter;
private String content;
public Chapters(String chapter_name, String chapter_content) {
chapter = chapter_name;
content = chapter_content;
}
#Override
public String toString() {
return "Chapter: " + chapter + " Content: " + content;
}
}
Notes:
Please ignore that the .set() method uses index 0, that's just for testing. The real function would use the chapter name's index.
Maybe you should use Set instead of a List? Change your
ArrayList<Chapters> allChapters = new ArrayList<>();
to - for example :
Set<Chapters> chapters = new HashSet<>();
To Set function correctly you should also implement equals(..) and hashCode() in your Chapters, for example, if you can rely only chapter
#Override
public int hashCode() {
return chapter.hashCode();
}
#Override
public boolean equals(Object obj) {
if (obj != null) {
if (obj instanceof Chapters) {
return chapter.contentEquals(((Chapters) obj).getChapter());
}
}
return false;
}
NOTE: above though working are just examples that use only chapter string as 'id' and not fully tested. See more What issues should be considered when overriding equals and hashCode in Java?.
There is no more need to check duplicates explicitly. You can just add chapters to your set and above changes will ensure no duplicates.
Turns out the main problem is the keyboard event. No matter which listener I use (KeyPressed, KeyReleased, KeyTyped) some kind of indexing error always pops up. I finally relented and gave the function its own button. It works perfectly now. This is the new code:
try {
String contentString = TAContent.getText();
int contentStringLen = contentString.length();
int selectedIndex = LSChapters.getSelectedIndex();
int ArrayIndexLength = sessionContent.size();
if (contentStringLen > 1) {
if (ArrayIndexLength < selectedIndex) {
for (int i = 0; i < selectedIndex; i++) {
sessionContent.add(0, "");
}
}
if (selectedIndex >= ArrayIndexLength) {
sessionContent.add(selectedIndex, contentString);
}
else {
sessionContent.set(selectedIndex, contentString);
}
}
else {
JOptionPane.showMessageDialog(null, "Please write chapter content first!");
}
}
catch (Exception e) {
System.err.println(e);
}
I'm new to OO. I've just started programming in Java for my university course.
I have a problem:
I have a method within the Club class to search for a member's name (or part of a name, according to my worksheet.
I have a class that tests this without me having to manually create objects from the Club class (I'm using BlueJ).
Here's the search method:
public void searchMember(String name){
i=0;
found = false;
while( i < members.size() && !found ){
if(members.contains( name )){
found = true;
}else{
i++;
}
}
if(found == true){
System.out.println(members.get(i));
}else{
System.out.println("Och Naw ... Member not found.");
}
}
And here is the testing class code:
public void demo()
{
club = new Club();
club.join(new Membership("Gordy Broon", 1, 1972));
club.join(new Membership("Eck Salmon", 9, 1965));
club.join(new Membership("Davie Caramel", 5, 1960));
System.out.println("Now doing some searching: ");
club.searchMember( "mon" );
System.out.println(" ");
System.out.println("And some more searching: ");
club.searchMember("moon");
System.out.println(" ");
}
Can someone explain to me why when searching for "mon" the result is not found?
To my understanding this should work.
I am new so ANY help and explanation would be amazing ^_^
Thanks!
You are comparing a String with a Membership. The contains method of List will go through every item in the list and check whether "mon".equals(membership), but a Membership object will presumably never return true that it is equal to some String.
(I am making an assumption about your Membership class, that you have not overridden the equals method from java.lang.Object. It would be possible to override equals so that it does return true when compared with a String, but there are two problems. One, you are expecting not just a match when they are equal, but a substring match (where "mon" matches "Eck Salmon"), and two, implementing equals this way would be a violation of its contract. It is expected that if a.equals(b) then b.equals(a), but no java.lang.String object is ever going to return true that it is equal to one of your Membership objects, and you can't modify java.lang.String to make it do that.)
What you want to do is go through the list and check if any of the membership objects have a name that contains "mon". I assume your Membership object has a getName() method:
for (Membership membership : members) {
if (membership.getName().contains(name)) {
System.out.println(membership);
return;
}
}
System.out.println("Och Naw ... Member not found.");
It is possible to do this a little more tersely in Java 8:
Optional<Membership> maybeMember = membership.stream()
.filter(m -> m.getName().contains(name)).findFirst();
String result = maybeMember.map(m -> m.toString())
.orElse("Och Naw ... Member not found.");
System.out.println(result);
This finds the first item in the list that matches the condition that its name must contain the specified name, and then maps it to a string using its toString method, or else uses the default string if no matching item from the list was found.
It seems that members is a list. So when you do members.contains( name ) it wont work. You beed to do the following members.get(i).getName().contains( name ).
I am trying to display all the strings used in a method invocation using SOOT program analysis framework. I am able to check for StringConstant but how do I get values for RefType ? Here is the sample code :
for (Value va : iv.getInvokeExpr().getArgs()) {
System.out.println("[ARGS : TYPE] " + va.getType() + " with ");
if (va instanceof StringConstant) {
System.out.print(va + " ");
} else if (va instanceof JimpleLocal) {
JimpleLocal jl = (JimpleLocal) va;
if (jl.getType() instanceof RefType) {
RefType rt = (RefType) jl.getType();
SootClass cls = rt.getSootClass();
String clsName = cls.getName();
// recursion possible - backward analysis ?
if(clsName.equals("java.lang.String")){
System.out.print("GOT STRING CLASS - HOW TO GET THE VALUE ?");
}
}
}
}
I am new to the program analysis domain, any pointers will be of great help.
Thanks
StringConstant had a getValue Methode. Just cast The value to this type. For locals your questions does not make sense, as they are variables, not constants.
I'm sorry if the question is a bit vague so i'll try to explain it.
I got this code:
public String toString()
{
String s = "text.\n";
for (Klus k : alleKlussen)
{
s += k.toString() + ".\n";
}
return s;
}
But I want to make different loops for different conditions.
For example, "Klus" has a couple of variables like: status, date etc.
I'm not very experienced with java yet, but would it be possible to do something like this:
for (Klus k : alleKlussen; status = "completed")
{..}
I know this is wrong but I'd like it to show all "Klus" objects where the status is "completed" and all "Klus" objects where the statis is "not completed".
Thanks and if anything is unclear or I used the wrong word for something, please tell me.
Edit:
It should make something like this:
if (k.getStatus().equals("completed"){
String s = "completed ones \n"
s += k.toString() + ".\n"; //get all completed ones
}
if (k.getStatus().equals("uncompleted"){
String s = "uncompleted ones \n"
s += k.toString() + ".\n"; //get all uncompleted ones
}
Simply add the condition inside the for() loop:
for (Klus k : alleKlussen) {
if (k.getStatus().equals("completed")) {
s += k.toString() + ".\n";
}
}
From the additional information in the question, it seems like the following is what is intended:
String completed = "completed ones \n";
String uncompleted = "uncompleted ones \n";
for (Klus k : alleKlussen) {
if (k.getStatus().equals("completed")) {
completed += k.toString() + ".\n"; //get all completed ones
}
else if (k.getStatus().equals("uncompleted")) {
uncompleted += k.toString() + ".\n"; //get all uncompleted ones
}
}
You should also consider using a StringBuilder to create the result strings, which reduces the memory overhead.
You can use switch if you have many conditions and it is easy to read
for (Klus k : alleKlussen)
{
switch(k.getStatus()){
case "completed": ....
break;
case "uncompleted": ....
break;
default: ...
}
}
Please note switch with String literals is only supported in Java 7.
Use this - this toString will print only Klus are completed.
public String toString()
{
String s = "text.\n";
for (Klus k : alleKlussen)
{
if("completed".equals(k.getStatus ()))
s += k.toString() + ".\n";
}
return s;
}
Why not just do the standard if-conditionals, such as:
if ("".equals(k.getStatus())) {
} else if ("completed".equals(k.getStatus())) {
}
To append the uncompleted after the completed ones, try this (And I suggest using enums, but you are welcome to stick to Strings. But then this will only work in Java SE 7!):
State.java:
// Makes switches easy to use and String typos are impossible
public enum State { COMPLETE, INCOMPLETE };
Replace your current String "state" with the enum like so:
Klus:java
public class Klus {
private State state;
...
public State getState() { return this.state; }
...
}
Now use it in a switch in the for loop. Use two strings, one for complete, one for incomplete. Append them in the end. (Note the use of StringBuilder instead of str +=... )
Class containing your toString():
public String toString() {
StringBuilder complete = new StringBuilder("completed ones \n"),
uncompleted = new StringBuilder("uncompleted ones \n");
for(Klus k : alleKlussen) {
switch(k.getStatus())
case COMPLETE:
complete.append(k.toString()).append(".\n"); break;
case INCOMPLETE:
uncompleted.append(k.toString()).append(".\n"); break;
default:
}
}
complete.append(uncompleted.toString();
return complete.toString();
}
I know someone will give me a hard time for this, but here goes. I am trying to convert some C code to Java and am still learning java as I go. I am having a very difficult time figuring out how to do this conversion and learning java for that matter. Any help or pointers on where to go would be greatly appreciated.
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}
printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* Jump to the selected adapter */
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
A conversion offering:
public class Item {
private String name;
private String description;
public Item(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return this.name;
}
public String getDescription() {
return this.description;
}
}
(defined elsewhere)
List<Item> items;
And now the code
int index = 1;
for (Item item: items) {
System.out.print(index + ". " + item.getName());
if (item.getDescription() != null) {
System.out.println(" (" + item.getDescription() + ")");
} else {
System.out.println"( (No Description Available)");
}
index++;
}
List<NetworkInterface> nets = Collections.list(NetworkInterface.getNetworkInterfaces());
if (nets.size() == 0) {
System.out.println();
System.out.println("No interfaces found! Make sure WinPcap is installed.");
return;
}
System.out.print("Enter the interface number(1-" + nets.size() + "):");
Byte[] input = new byte[100];
System.in.read(input);
String inString = new String(input);
int interfaceIndex = Integer.getInteger(inString);
if (interfaceIndex < 1 || interfaceindex > nets.size()) {
System.out.println();
System.out.println("Interface number out of range.");
// freeing items is done by dereferencing
nets = null;
return;
}
// jump to the selected adapter
NetworkInterface selectedInterface = nets.get(interfaceIndex);
Note that you will have to do the "real" conversion of the rest of the program; that is writing a PCap solution in Java, or writing a JNI (Java) interface to call the PCap library routines.
WinPcap will always require native coding. You could use JNI to get some of that code (e.g. the select interface part) to java, but you'll never be able to fully convert it. (You can't directly call native dll's from java)
I can't really give you examples on JNI, but there is enough out there to find when searching JNI and Tutorial or the like :).
Java does not have pointers, so a construct like "d->next" won't map 1:1 in Java.
You'll have to figure out how to create a Java object that corresponds to whatever your "d" is. The rest looks like simple iteration and calls to System.out.
What do you mean by conversion?Are you trying to write an equivalent C program to Java?Is it an existing project or you wrote a program in C first and now you want to write the same program in Java?In any case you should get a good grip with both languages because they differ in the way you write programs that is C is a imperative/procedural language whereas Java is an object-oriented one. This alone means programming 'style' varies differently due to language semantics (and programming patterns, while language-agnostic, are applied differently too).
P.S.: I assume you are a beginner which, if I am correct, does not justify your votes down.